/**
 * Description: WebAudio interface of Synthesizer.
 *
 * @package     midi-Synth
 * @category    module js
 * @author      Oleg Klenitsky <https://adminkov.bcr.by/midi/>
 * @copyright
 * @license     GPL-2.0-or-later
 */

"use strict";

var standMidi = "GM";
var audiograph_node_click;
var audiograph_node = "";
var viewOscillograph = false;

var curBank;
var curPreset;
var curProg;
var curOct;
var curNote;
var curCh;

var midiPort     = [];
var currentPort  = -1;
var canvas_midi;
var synth;
var kbd;

var pressBtn = "";

var audiograph_click  = false;
var audiograph_move   = false;
var canvas_audiograph = false;
var canvas_midi_click = false;
var sh_mousedown      = false;
var sh_mouseup        = false;
var vol_change_event  = false;
var rev_change_event  = false;

var compThreshold_change_event = false;
var compKnee_change_event       = false;
var compRatio_change_event      = false;
var compAttack_change_event     = false;
var compRelease_change_event    = false;

var conv_duration_change_event = false;
var conv_decay_change_event  = false;

var cnv_vert_kbd_mousedown  = false;
var cnv_vert_kbd_mouseup    = false;

var prog_change_event       = false;
var oct_change_event        = false;
var ch_change_event         = false;
var qlt_change_event        = false;
var sus_change_event        = false;
var loop_change_event       = false;
var scaleX_change_event     = false;
var scaleY_change_event     = false;
var prog_num_input_event    = false;

window.onload = () => {
  InitApp();
  openSoundFontsDB().then(result => checkStandardSF());
}

/**
 * Main function.
 */
function InitApp(){
  InitMidi();

  canvas_midi = document.getElementById("canvas_midi");
  synth       = document.getElementById("tinysynth");
  kbd         = document.getElementById("kbd");

  var srcMidi  = synth.getMidiSrc();
  midiFile     = new MIDIFile(srcMidi);

  kbd.addEventListener("change", KeyIn);

  var inform_panel = document.getElementById("inform_panel");
  var audiograph   = document.getElementById("audiograph");
  var prog_num     = document.getElementById("prog_num");
  var scaleX       = document.getElementById("scaleX");
  var scaleY       = document.getElementById("scaleY");
  var prog         = document.getElementById("prog");
  var vol          = document.getElementById("vol");
  var rev          = document.getElementById("rev");

  var comp_threshold = document.getElementById("comp_threshold");
  var comp_knee      = document.getElementById("comp_knee");
  var comp_ratio     = document.getElementById("comp_ratio");
  var comp_attack    = document.getElementById("comp_attack");
  var comp_release   = document.getElementById("comp_release");

  var conv_duration = document.getElementById("conv_duration");
  var conv_decay   = document.getElementById("conv_decay");
  var oct          = document.getElementById("oct");
  var ch           = document.getElementById("ch");
  var qlt          = document.getElementById("qlt");
  var sus          = document.getElementById("sus");
  var loop         = document.getElementById("loop");
  var sh           = document.getElementById("shotBtn");
  var cnv_vert_kbd = document.getElementById("canvas_rangeNotes_part2");

  sh.innerHTML = "C4";
  curNote      = 60;
  curProg      = 0;
  curOct       = 0;
  curCh        = 0;

  synth.ready().then(()=>{
    if (false == canvas_midi_click) {
      canvas_midi.addEventListener("click", function(e) {
        if (false == viewOscillograph) {
          viewOscillograph = true;
        }else{
          viewOscillograph = false;
          gridOscillograph(false);
        }
        OscillographDiagram(scaleX.value);
      });
      canvas_midi_click = true;
    }

    if (false == cnv_vert_kbd_mousedown) {
      cnv_vert_kbd.addEventListener("mousedown",function(e) {
        let cnvRangeNotesCoords = getCoords(cnv_vert_kbd);

        let posX = parseInt(e.clientX - cnvRangeNotesCoords.left);
        let posY = parseInt(e.clientY - cnvRangeNotesCoords.top);
        let curPosY;

        for(let i=0; i < arrNotesTrack.length; i++){
          if( arrNotesTrack[i] < posY && posY < arrNotesTrack[i+1]){
            posY = arrNotesTrack[i];
            curPosY = arrNotesTrack.length - i;
            break;
          }
        }
        if(undefined == curPosY) return;

        curNote = curPosY + 20;

        ctxRange.strokeStyle = "black";
        ctxRange.fillStyle   = "#C3C3C3";
        ctxRange.strokeRect(2, posY, 40, 10);
        ctxRange.fillRect(2, posY, 40, 10);

        let keyNum = synth.arrNotes[curNote-21];
        document.getElementById("shotBtn").innerHTML= (keyNum) ? keyNum :"--";

        if(9 == curCh){
          prog.value = curNote;
          ProgChange();
          let prog_num = curNote;
          document.getElementById("prog_num").value = prog_num;
          let prog_name = synth.getProgNameGM(1,curNote-35);
          document.getElementById("prog_name").innerHTML = prog_name;

          document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + prog_num + "] " + prog_name;

          var w=synth.drummap[curNote-35];
          if(undefined == w){
            document.getElementById("prog1").style.visibility = "hidden";
            document.getElementById("prog2").style.visibility = "hidden";
            document.getElementById("prog3").style.visibility = "hidden";
            document.getElementById("prog4").style.visibility = "hidden";
            document.getElementById("oscs").style.visibility = "hidden";
            document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
            return;
          }
          document.getElementById("oscs").style.visibility = "visible";

          ViewParam(w);
          EnableRow();
          audioNodesDiagram();
        }else{
          if("GM" == standMidi){
            audioNodesDiagram();
          }else{
            let dataNote = soundFont.getKeyData(curBank, curProg, curNote);
            if(null == dataNote){
              document.getElementById("inform_panel").style.color = "red";
              document.getElementById("inform_panel").innerHTML = "Out of keyRange";
              return;
            }else{
              document.getElementById("inform_panel").style.color = "#A0A378";
              document.getElementById("inform_panel").innerHTML = "midi-Synth is ready";
            }
            let preset = dataNote.preset;
            let activeZones = synth.getProgNoteSF(curBank, curProg, curNote);

            if(undefined == activeZones) {
              activeZones = getActiveZones(preset, curNote);
              synth.setProgNoteSF(curBank, curProg, curNote, activeZones);
            }
            tblTimbreSF(activeZones);
            audioNodesDiagram();
          }
        }
        //noteOn...
        synth.send([0x90+curCh,curNote+curOct*12,100]);
        kbd.setNote(1, curNote);
      });
      cnv_vert_kbd_mousedown = true;
    }
    if (false == cnv_vert_kbd_mouseup) {
      cnv_vert_kbd.addEventListener("mouseup",function(e) {
        synth.send([0x80+curCh,curNote+curOct*12,0]);
        audioNodesDiagram();
        kbd.setNote(0, curNote+curOct*12);
        drawVertKbd();
        cnv_vert_kbd_mouseup = true;
      });
    }

    if (false == sh_mousedown) {
      sh.addEventListener("mousedown",function(e) {
        if(ctxRange){
          let lastIndex = arrNotesTrack.length-1;
          let posY = arrNotesTrack[lastIndex-(curNote-21)-curOct*12];
          ctxRange.strokeStyle = "black";
          ctxRange.fillStyle   = "#C3C3C3";
          ctxRange.strokeRect(2, posY, 40, 10);
          ctxRange.fillRect(2, posY, 40, 10);
        }
        if(9 == curCh){
          prog.value = curNote;
          ProgChange();
          let prog_num = curNote;
          document.getElementById("prog_num").value = prog_num;
          let prog_name = synth.getProgNameGM(1,curNote-35);
          document.getElementById("prog_name").innerHTML = prog_name;

          document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + prog_num + "] " + prog_name;

          var w=synth.drummap[curNote-35];
          if(undefined == w){
            document.getElementById("prog1").style.visibility = "hidden";
            document.getElementById("prog2").style.visibility = "hidden";
            document.getElementById("prog3").style.visibility = "hidden";
            document.getElementById("prog4").style.visibility = "hidden";
            document.getElementById("oscs").style.visibility = "hidden";
            document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
            return;
          }
          document.getElementById("oscs").style.visibility = "visible";

          ViewParam(w);
          EnableRow();
          audioNodesDiagram();
        }else{
          if("GM" == standMidi){
            audioNodesDiagram();
          }else{
            let dataNote = soundFont.getKeyData(curBank, curProg, curNote);
            if(null == dataNote){
              document.getElementById("inform_panel").style.color = "red";
              document.getElementById("inform_panel").innerHTML = "Out of keyRange";
              return;
            }else{
              document.getElementById("inform_panel").style.color = "#A0A378";
              document.getElementById("inform_panel").innerHTML = "midi-Synth is ready";
            }
            let preset = dataNote.preset;
            let activeZones = synth.getProgNoteSF(curBank, curProg, curNote);

            if(undefined == activeZones) {
              activeZones = getActiveZones(preset, curNote);
              synth.setProgNoteSF(curBank, curProg, curNote, activeZones);
            }
            tblTimbreSF(activeZones);
            audioNodesDiagram();
          }
        }
        //noteOn...
        synth.send([0x90+curCh,curNote+curOct*12,100]);
        kbd.setNote(1, curNote);
      });
      sh_mousedown = true;
    }
    if (false == sh_mouseup) {
      sh.addEventListener("mouseup",function(e) {
        synth.send([0x80+curCh,curNote+curOct*12,0]);
        audioNodesDiagram();
        kbd.setNote(0, curNote+curOct*12);
        drawVertKbd();
      });
      sh_mouseup = true;
    }
    if (false == vol_change_event) {
      vol.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.masterVol=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
       drawInfoBox();
      });
      vol_change_event = true;
    }
    if (false == rev_change_event) {
      rev.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.reverbLev=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      rev_change_event = true;
    }
    if (false == compThreshold_change_event) {
      comp_threshold.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.compThreshold=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      compThreshold_change_event = true;
    }
    if (false == compKnee_change_event) {
      comp_knee.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.compKnee=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      compKnee_change_event = true;
    }
    if (false == compRatio_change_event) {
      comp_ratio.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.compRatio=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });

      compRatio_change_event = true;
    }
    if (false == compAttack_change_event) {
      comp_attack.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.compAttack=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      compAttack_change_event = true;
    }
    if (false == compRelease_change_event) {
      comp_release.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.compRelease=e.target.value;
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      compRelease_change_event = true;
    }

    if (false == conv_duration_change_event) {
      conv_duration.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.convDuration=e.target.value.toFixed(2);
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      conv_duration_change_event = true;
    }
    if (false == conv_decay_change_event) {
      conv_decay.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.convDecay=e.target.value.toFixed(2);
        }
        if(false == synth.playing){
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            clearTimeout(interval);
          }, 500);
        }
        drawInfoBox();
      });
      conv_decay_change_event = true;
    }

    if (false == prog_change_event) {
      prog.addEventListener("change",function(e) {
        curProg = e.target.value;
        ProgChange();

        if("GM" == standMidi){
          tblTimbreGM();
          //reset sw0-sw4
          p_swX_click("sw0");
        }else{
          let progName = synth.getProgNameSF(curBank, curProg);
          document.getElementById("prog_num").value = curProg;
          document.getElementById("prog_name").innerHTML = progName;
          document.getElementById("Preset_th1").innerHTML = " Preset "+curProg;
          let itemsTd = document.getElementById("presets").childNodes;
          let docPrm = "";

          itemsTd.forEach(function(item, index){
            let itm = item.firstChild;
            if(itm.innerHTML){
              if(itm.innerHTML == progName){
                item.style.backgroundColor = "#E3E3E3";
              }else{
                item.style.backgroundColor = "white";
              }
            }else{
              if(itm.textContent == progName){
                item.style.backgroundColor = "#E3E3E3";
              }else{
                item.style.backgroundColor = "white";
              }
            }
          });

          let numBank = 0;
          let dataNote = soundFont.getKeyData(numBank, curProg, curNote);

          if(null !== dataNote){
            let preset = dataNote.preset;
            let activeZones = synth.getProgNoteSF(curProg, curNote);

            if(undefined == activeZones) {
              activeZones = getActiveZones(preset, curNote);
              synth.setProgNoteSF(curProg, curNote, activeZones);
            }
            tblTimbreSF(activeZones);

            //Озвучить ноту загруженного soundFonts
            if(false == synth.playing){
              kbd.setNote(1, curNote);
              synth.send([0x90+curCh,curNote+curOct*12,100]);
              let interval = setTimeout(() => {
                kbd.setNote(0, curNote);
                synth.send([0x80+curCh,curNote+curOct*12,0]);
                audioNodesDiagram();
                clearTimeout(interval);
              }, 500);
            }
          }
        }
      });
      prog_change_event = true;
    }
    if (false == oct_change_event) {
      oct.addEventListener("change",function(e) {
        if(false == synth.playing){
          OctChange(e.target.value);
          if(ctxRange){
            let lastIndex = arrNotesTrack.length-1;
            let posY = arrNotesTrack[lastIndex-curNote-curOct*12];
            ctxRange.strokeStyle = "black";
            ctxRange.fillStyle   = "#C3C3C3";
            ctxRange.strokeRect(2, posY, 40, 10);
            ctxRange.fillRect(2, posY, 40, 10);
          }
          sh.innerHTML=synth.arrNotes[curNote+curOct*12];
          kbd.setNote(1, curNote+curOct*12);
          synth.send([0x90+curCh,curNote+curOct*12,100],0);
          let interval = setTimeout(() => {
            kbd.setNote(0, curNote+curOct*12);
            drawVertKbd();
            synth.send([0x80+curCh,curNote+curOct*12,100],0);
            audioNodesDiagram();
            clearTimeout(interval);
          }, 500);
        }
      });
      oct_change_event = true;
    }
    if (false == ch_change_event) {
      ch.addEventListener("change",function(e) {
        curCh = e.target.value - 1;
        if(false == synth.playing){
          if(ctxRange){
            let lastIndex = arrNotesTrack.length-1;
            let posY = arrNotesTrack[lastIndex-curNote-curOct*12];
            ctxRange.strokeStyle = "black";
            ctxRange.fillStyle   = "#C3C3C3";
            ctxRange.strokeRect(2, posY, 40, 10);
            ctxRange.fillRect(2, posY, 40, 10);
          }

          if(curCh==9){
            ProgChange();
            var w=synth.drummap[curNote-35];
            if(undefined == w){
              document.getElementById("prog1").style.visibility = "hidden";
              document.getElementById("prog2").style.visibility = "hidden";
              document.getElementById("prog3").style.visibility = "hidden";
              document.getElementById("prog4").style.visibility = "hidden";
              document.getElementById("oscs").style.visibility = "hidden";
              document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
              return;
            }
            document.getElementById("soundeditorGM").style.display = "table";
            document.getElementById("soundViewerGSXG").style.display = "none";

            document.getElementById("oscs").style.visibility = "visible";

            ViewParam(w);
            EnableRow();
            audioNodesDiagram();
          }else{
            if("GM" == standMidi){
              document.getElementById("soundeditorGM").style.display = "table";
              document.getElementById("soundViewerGSXG").style.display = "none";

              audioNodesDiagram();
            }else{
              document.getElementById("soundeditorGM").style.display = "none";
              document.getElementById("soundViewerGSXG").style.display = "table";

              let dataNote = soundFont.getKeyData(curBank, curProg, curNote);
              let preset = dataNote.preset;
              let activeZones = synth.getProgNoteSF(curBank, curProg, curNote);

              if(undefined == activeZones) {
                activeZones = getActiveZones(preset, curNote);
                synth.setProgNoteSF(curBank, curProg, curNote, activeZones);
              }
              tblTimbreSF(activeZones);
              audioNodesDiagram();
            }
            kbd.setNote(1, curNote);
            synth.send([0x90+curCh,curNote+curOct*12,100],0);
            let interval = setTimeout(() => {
              kbd.setNote(0, curNote);
              drawVertKbd();
              synth.send([0x80+curCh,curNote+curOct*12,100],0);
              clearTimeout(interval);
            }, 500);
          }
        }
      });
      ch_change_event = true;
    }
    if (false == qlt_change_event) {
      qlt.addEventListener("change",function(e) {
        SetQuality(e.target.value);
        tblTimbreGM();
      });
      qlt_change_event = true;
    }
    if (false == sus_change_event) {
      sus.addEventListener("change",function(e) {
        if (0 == e.target.value) {
            Sustain(false);
          }else{
            Sustain(true);
        }
      });
      sus_change_event = true;
    }
    if (false == loop_change_event) {
      loop.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.loop=e.target.checked;
        }
      });
      loop_change_event = true;
    }
    if (false == scaleX_change_event) {
      var analyzerMain = synth.getAnalyzerMain();

      scaleX.addEventListener("change",function(e) {
        OscillographDiagram(e.target.value);
      });
      scaleX_change_event = true;
    }
    if (false == scaleY_change_event) {
      scaleY.addEventListener("change",function(e) {
        if(typeof(synth)!="undefined"){
          synth.analysVol=e.target.value;
        }
      });
      scaleY_change_event = true;
    }
    if (false == prog_num_input_event) {
      prog_num.addEventListener("input",function(e) {
        curProg = e.target.value;
        ProgChange();
        document.getElementById("prog_name").innerHTML = synth.getProgNameGM(0, curProg);
      });
      prog_num_input_event = true;
    }
    if (false == audiograph_move) {
      audiograph.addEventListener("mousemove",function(e) {
        audiograph_check_pos(e);
      });
    }
    if (false == audiograph_click) {
      audiograph.addEventListener("click",function(e) {
        audiograph_node_click = audiograph_node;
        drawInfoBox();
      });
    }

    synth.analysVol = 4;
    document.getElementById("prog").value = "0";
    document.getElementById("prog_num").value = "0";
    document.getElementById("prog_name").innerHTML = synth.getProgNameGM(0, 0);

    //Первый старт
  }).then(() => {
    ProgChange();
    tblTimbreGM();
    gridOscillograph(false);
  });
}

/**
 * Check standard SoundFonts
 * @return {[type]} [description]
 */
function checkStandardSF(){
  let itemsGS = localStorage.getItem("soundFontsGS");
  let itemsXG = localStorage.getItem("soundFontsXG");
  let itemCheckedGS;
  let itemCheckedXG;

  document.getElementById("GS").style.visibility = "hidden";
  document.getElementById("p_GS").style.visibility = "hidden";

  document.getElementById("XG").style.visibility = "hidden";
  document.getElementById("p_XG").style.visibility = "hidden";

  let checkedGS = false;
  if("" !== itemsGS && null !== itemsGS){
    let tbody = document.createElement("tbody");
    tbody.innerHTML = itemsGS;
    itemCheckedGS = tbody.querySelector(`input[name=soundFontsGS]:checked`);
    if(itemCheckedGS) {
      checkedGS = true;
      document.getElementById("GS").setAttribute("soundfonts", itemCheckedGS.value);
    }else{
      document.getElementById("GS").setAttribute("soundfonts", "");
    }
  }
  if(true == checkedGS){
    document.getElementById("GS").style.visibility = "visible";
    document.getElementById("p_GS").style.visibility = "visible";
  }else{
    document.getElementById("GS").style.visibility = "hidden";
    document.getElementById("p_GS").style.visibility = "hidden";
  }

  let checkedXG = false;
  if("" !== itemsXG && null !== itemsXG){
    let tbody = document.createElement("tbody");
    tbody.innerHTML = itemsXG;
    itemCheckedXG = tbody.querySelector(`input[name=soundFontsXG]:checked`);
    if(itemCheckedXG) {
      checkedXG = true;
      document.getElementById("XG").setAttribute("soundfonts", itemCheckedXG.value);
    }else{
      document.getElementById("XG").setAttribute("soundfonts", "");
    }
  }
  if(true == checkedXG){
    document.getElementById("XG").style.visibility = "visible";
    document.getElementById("p_XG").style.visibility = "visible";
  }else{
    document.getElementById("XG").style.visibility = "hidden";
    document.getElementById("p_XG").style.visibility = "hidden";
  }
}
function addRecNewNote(noteNum){
  let ppqn = synth.getPPQN();
  let valTransform = "scale("+scale+", 1)";
  let ch = document.getElementById("part1_" + selTrackNum + "_ch").innerHTML;
  ch = ch.split(":");
  ch = parseInt(ch[1]-1);

  let posY = arrNotesTrack[Math.abs(noteNum-88)];

  let action = "";
  changedData = true;

  let rect = document.createElementNS(svgns, "rect");
  rect.setAttribute("trk", selTrackNum);
  rect.setAttribute("ch", ch);
  rect.setAttribute("note", noteNum);
  rect.setAttribute("velocity", arrNotesRecord[noteNum].velocity);
  rect.setAttribute("x", arrNotesRecord[noteNum].offset/12);
  rect.setAttribute("y", posY);
  rect.setAttribute("width", arrNotesRecord[noteNum].delta/12);
  rect.setAttribute("height", 8);
  rect.setAttribute("fill", "#0073AA");
  rect.style.transform = valTransform;

  rect.addEventListener("contextmenu", function(e) {
    rect.remove();
  });
  rect.addEventListener("mousedown", function(e){
    action = rect.style.cursor;
    rect.style.opacity = "0.4";

    let rectCoords  = getCoords(rect);
    let svgBodyCoords = getCoords(svgBody);
    let shiftX = (e.clientX - rectCoords.left);
    let svgBodyMin = (svgBodyCoords.left + shiftX);
    let svgBodyMax = (svgBodyCoords.left + svgBodyCoords.width - rectCoords.width + shiftX);

    function resizeAt(e){
      let posRectLeft = rectCoords.left - svgBodyCoords.left;
      let width = (e.clientX - svgBodyCoords.left - shiftX - posRectLeft + rectCoords.width)/scale;
      rect.attributes.width.value = (width > ppqn/4/12) ?width :ppqn/4/12;
      rect.setAttribute("fill", "red");
      svgBody.setAttribute("action", "note_resize");
    }
    function moveAt(e){
      let left = (e.clientX - svgBodyCoords.left - shiftX)/scale;
      if(e.clientX < svgBodyMin) left = 0;
      if(e.clientX > svgBodyMax) left = svgBodyCoords.width - rectCoords.width;
      rect.attributes.x.value = left;
      rect.setAttribute("fill", "green");
      svgBody.setAttribute("action", "note_move");
    }
    document.onmousemove = function(e){
      if("move" == action) {
        moveAt(e);
        svgBody.setAttribute("action", "note_move");
      }
      if("ew-resize" == action) {
        resizeAt(e);
        svgBody.setAttribute("action", "note_resize");
      }
    }
    document.onmouseup = function(e){
      document.onmousemove = null;
      document.onmouseup = null;
      svgBody.setAttribute("action", "");
    }
  });
  rect.addEventListener("mouseup",function(e){
    let chunk = 0;
    action = "";
    rect.style.opacity = "1";
    //update leftSide position
    chunk = rect.attributes.x.value%(Math.round(ppqn/4/12));
    rect.attributes.x.value = rect.attributes.x.value - chunk;
    //update rect width
    let rectWidth = rect.attributes.width.value;
    let rectWidthMin = Math.round(ppqn/4/12);
    if(rectWidth < rectWidthMin)rectWidth = rectWidthMin;
    chunk = rectWidth%(rectWidthMin);
    rect.attributes.width.value = rect.attributes.width.value - chunk;
  });
  rect.addEventListener("mousemove",function(e){
    let mouseX = e.offsetX;

    let posX = parseInt(rect.attributes.x.value)*scale;
    let noteWidth = parseInt(rect.attributes.width.value)*scale;

    if (posX < mouseX && mouseX < posX + noteWidth-2){
      rect.style.cursor = "move";
    }
    if (posX+noteWidth-2 < mouseX && mouseX < posX+noteWidth+2){
      rect.style.cursor = "ew-resize";
    }
  });
  svgBody.appendChild(rect);
}
function MidiIn(e){
  let ppqn = synth.getPPQN();

  curNote = e.data[1];

  if(synth){
    if(0 == e.data[2]){
      //noteOff
      synth.send([0x80+curCh,curNote+curOct*12,0]);
      drawVertKbd();
      kbd.setNote(0, curNote);
      audioNodesDiagram();
    }else{
      //noteOn
      synth.send([0x90+curCh,curNote+curOct*12,100]);
      kbd.setNote(1, curNote);
      if(ctxRange){
        let lastIndex = arrNotesTrack.length-1;
        let posY = arrNotesTrack[lastIndex-(curNote-21)-curOct*12];
        ctxRange.strokeStyle = "black";
        ctxRange.fillStyle   = "#C3C3C3";
        ctxRange.strokeRect(2, posY, 40, 10);
        ctxRange.fillRect(2, posY, 40, 10);
      }
    }

    e.data[0] = e.data[0] + curCh;
    e.data[1] = e.data[1] + curOct * 12;

    if("btn_record" == pressBtn && "" !== selTrackNum) {
      let numNote = e.data[1];
      //noteOn...
      if(0 !== e.data[2]){
        arrNotesRecord[numNote] = {"offset":(rec_cur_tick-ppqn/4), "delta":0, "velocity":e.data[2]};
      }else{
      //noteOff...
        arrNotesRecord[numNote].delta = (rec_cur_tick-ppqn/4) - arrNotesRecord[numNote].offset;
        addRecNewNote(numNote);
      }
    }
    document.getElementById("shotBtn").innerHTML=synth.arrNotes[curNote-21];
  }
}
function SelectMidi(n){
  document.getElementById("sel_kbd").selectedIndex = n+1;
  if(currentPort >= 0)
    midiPort[currentPort].removeEventListener("midimessage", MidiIn);
  currentPort = n;
  if(currentPort >= 0){
    midiPort[currentPort].addEventListener("midimessage", MidiIn);
  }
}
function InitMidi(){
  if(navigator.requestMIDIAccess){
    navigator.requestMIDIAccess().then(
      function(access){
        console.log("MIDI ready.");
        setTimeout(function(){
          var it = access.inputs.values();
          for(var i = it.next(); !i.done; i = it.next()){
            var e = document.createElement("option");
            e.innerHTML = i.value.name;
            document.getElementById("sel_kbd").appendChild(e);
            midiPort.push(i.value);
          }
          if(midiPort.length > 0)
            SelectMidi(0);
        },10);
      },
      function(){
        console.log("MIDI is not available.");
      }
    );
  }
}
function loadMidi(files){
  var reader = new FileReader();

  reader.onload=function(e){
    if(synth){
      synth.loadMIDI(e.target.result);
      midiFile = new MIDIFile(e.target.result);

      document.getElementById("subwin_part2").scrollLeft = 0;
      document.getElementById("sequencer_subfooter2").scrollLeft = 0;

      document.getElementById("ptrTime").style.left = "0px";
      document.getElementById("ptrTimeStave").style.left = "0px";

      //Reset other prm
      scale = 1;
      changedData = false;
      stave.innerHTML = "";
      selTrackNum = "";
      pressBtn    = "";
      arrMeasures = [];
      arrVexFlow  = [];
      errMidi = [];
      initArrTools();

      resetAllBtns();

      document.getElementById("ptrTimeStave").style.display = "none";
      document.getElementById("btnsStave").style.display = "none";

      Sequencer();
      document.getElementById("inform_panel").innerHTML = "["+files[0].name + "] file loaded";
      document.getElementById("sequencerBtn").removeAttribute("disabled");
    }
  }
  if(0 !== files.length){
    reader.readAsArrayBuffer(files[0]);

    document.getElementById("inform_panel").innerHTML = "";
    document.getElementById("sequencerBtn").setAttribute("disabled", true);

    //loader on
    let loader5 = document.createElement("div");
    loader5.className = "loader5";
    document.getElementById("inform_panel").appendChild(loader5);

    document.getElementById("file_name_midi").value = files[0].name;
    document.getElementById("file_size_midi").value = formatBytes(files[0].size);
  }else{
    if (synth) {
      synth.src = null;
      document.getElementById("inform_panel").innerHTML = "MIDI file not loaded";
    }
  }
}
/**
 * Reset all btns
 */
function resetAllBtns(){
  document.getElementById("btn_verify").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_trackInfo").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_stave").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_tools").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_help").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_export").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_record").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_report").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_setting").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_about").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_examples").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_errors").style.boxShadow =
  "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
  document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

  pressBtn = "";

  document.getElementById("stave").innerHTML = "";
  document.getElementById("stave").style.background = "#C3C3C3";
  document.getElementById("btnsStave").style.display = "none";
  document.getElementById("ptrTimeStave").style.display = "none";
}
function KeyIn(e){
  //imgs
  document.getElementById("canvas_imgs").style.display = "none";

  curNote=e.note[1]+curOct*12;

  let keyNum = synth.arrNotes[curNote-21];
  document.getElementById("shotBtn").innerHTML= (keyNum) ? keyNum :"--";

  if(curCh==9){
    prog.value = e.note[1];
    ProgChange();
    let prog_num = e.note[1];
    document.getElementById("prog_num").value = prog_num;
    let prog_name = synth.getProgNameGM(1,curNote-35);
    document.getElementById("prog_name").innerHTML = prog_name;

    document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + prog_num + "] " + prog_name;

    var w=synth.drummap[curNote-35];
    if(undefined == w){
      document.getElementById("prog1").style.visibility = "hidden";
      document.getElementById("prog2").style.visibility = "hidden";
      document.getElementById("prog3").style.visibility = "hidden";
      document.getElementById("prog4").style.visibility = "hidden";
      document.getElementById("oscs").style.visibility = "hidden";
      document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
      return;
    }
    document.getElementById("oscs").style.visibility = "visible";

    ViewParam(w);
    EnableRow();
    audioNodesDiagram();
  }else{
    if("GM" == standMidi){
    audioNodesDiagram();
    }else{
      let dataNote = soundFont.getKeyData(curBank, curProg, curNote);
      if(null == dataNote){
        document.getElementById("inform_panel").style.color = "red";
        document.getElementById("inform_panel").innerHTML = "Out of keyRange";
        return;
      }else{
        document.getElementById("inform_panel").style.color = "#A0A378";
        document.getElementById("inform_panel").innerHTML = "midi-Synth is ready";
      }
      let preset = dataNote.preset;
      let activeZones = synth.getProgNoteSF(curBank, curProg, curNote);

      if(undefined == activeZones) {
        activeZones = getActiveZones(preset, curNote);
        synth.setProgNoteSF(curBank, curProg, curNote, activeZones);
      }
      tblTimbreSF(activeZones);
      audioNodesDiagram();
    }
  }
  if(e.note[0]){
    if(ctxRange){
      let lastIndex = arrNotesTrack.length-1;
      let posY = arrNotesTrack[lastIndex-(curNote-21)-curOct*12];
      ctxRange.strokeStyle = "black";
      ctxRange.fillStyle   = "#C3C3C3";
      ctxRange.strokeRect(2, posY, 40, 10);
      ctxRange.fillRect(2, posY, 40, 10);
    }
    //noteOn...
    synth.send([0x90+curCh,curNote+curOct*12,100]);
    if("btn_record" == pressBtn && "" !== selTrackNum) {
      arrNotesRecord[curNote] = {"offset":rec_cur_tick, "delta":0, "velocity":100};
    }
  }else{
    drawVertKbd();
    synth.send([0x80+curCh,curNote+curOct*12,0]);
    //noteOff...
    if("btn_record" == pressBtn && "" !== selTrackNum) {
      arrNotesRecord[curNote].delta = rec_cur_tick - arrNotesRecord[curNote].offset;
      addRecNewNote(curNote);
    }
  }
}
function ViewDef(pg){
  let str = "";
  let progNum = document.getElementById("prog_num");
  let patch_load = document.getElementById("patch_load");
  let patch_del  = document.getElementById("patch_del");

  pg.p.forEach(function(item, index){
    str += JSON.stringify(item)+";";
  });
  str = str.slice(0, -1);

  document.getElementById("patch").value = str;

  str = localStorage.getItem("Prog_"+progNum.value+"_patch");
  if(null !== str){
    patch_load.style.color="green";
    if(undefined !== patch_load.attributes.disabled) patch_load.removeAttribute("disabled");
    patch_del.style.color="green";
    if(undefined !== patch_del.attributes.disabled) patch_del.removeAttribute("disabled");
  }else{
    patch_load.style.color="red";
    patch_load.setAttribute("disabled","");
    patch_del.style.color="red";
    patch_del.setAttribute("disabled","");
  }
}

function EnableRow(){
  var oscs=document.getElementById("oscs").selectedIndex+1;
  var ids=["g","w","v","t","f","a","h","d","s","r","p","q","k"];

  for(var i=1;i<=4;++i){
    if(i<=oscs){
      document.getElementById("prog"+i).style.visibility = "visible";
    }else{
      document.getElementById("prog"+i).style.visibility = "hidden";
    }
    for(var id=0;id<ids.length;++id){
      document.getElementById(ids[id]+i).disabled = (oscs>=i) ?false :true;
      if (oscs>=i) {
        document.getElementById(ids[id]+i).setAttribute("style","font-weight:bold;text-align: center;");
        document.getElementById("sw"+i).style.visibility="visible";
        document.getElementById("p_sw"+i).style.visibility="visible";
      }else{
        document.getElementById(ids[id]+i).setAttribute("style","font-weight:bold;background:#cccf;text-align: center;");
        document.getElementById("sw"+i).style.visibility="hidden";
        document.getElementById("p_sw"+i).style.visibility="hidden";
      }
      switch(i){
        case 1:
          document.getElementById(ids[id]+i).style.color="red";
          break;
        case 2:
          document.getElementById(ids[id]+i).style.color="blue";
          break;
        case 3:
          document.getElementById(ids[id]+i).style.color="green";
          break;
        case 4:
          document.getElementById(ids[id]+i).style.color="brown";
          break;
      }
    }
  }
}
function tblTimbreGM(){
  var td_osc_num = document.getElementsByClassName("osc_num");
  var prog;

  for (let i = 0; i < 3; i++) {
    td_osc_num[i].innerHTML = "";
  }

  if(curCh==9){
    prog=synth.drummap[curNote-35];
  }else{
    prog=synth.program[curProg];
  }

  if(!prog)return;

  var oscs=document.getElementById("oscs").selectedIndex+1;

  EnableRow();

  prog.p = [];
  for(var i=0;i<oscs;++i) {
    prog.p.push({g:0,w:"sine",v:0,t:0,f:0,a:0,h:0,d:0,s:0,r:0,p:0,q:0,k:0});
  }
  for(var i=0;i<oscs;++i){
    prog.p[i].g=GetVal("g"+(i+1));
    prog.p[i].w=document.getElementById("w"+(i+1)).value;
    prog.p[i].v=GetVal("v"+(i+1));
    prog.p[i].t=GetVal("t"+(i+1));
    prog.p[i].f=GetVal("f"+(i+1));
    prog.p[i].a=GetVal("a"+(i+1));
    prog.p[i].h=GetVal("h"+(i+1));
    prog.p[i].d=GetVal("d"+(i+1));
    prog.p[i].s=GetVal("s"+(i+1));
    prog.p[i].r=GetVal("r"+(i+1));
    prog.p[i].p=GetVal("p"+(i+1));
    prog.p[i].q=GetVal("q"+(i+1));
    prog.p[i].k=GetVal("k"+(i+1));
  }

  if(false == synth.playing){
    kbd.setNote(1, curNote);
    synth.send([0x90+curCh,curNote+curOct*12,100]);
    let interval = setTimeout(() => {
      kbd.setNote(0, curNote);
      synth.send([0x80+curCh,curNote+curOct*12,0]);
      clearTimeout(interval);
    }, 500);
  }

  document.getElementById("descr_ul").innerHTML = "Description of table fields";
  document.getElementById("descr_ul").setAttribute("style", "margin:0;padding:0;margin-top:100px;color:white;text-align: center;font-family: 'Arial, Helvetica, sans-serif';");

  audioNodesProgName().then(result => audioNodesDiagram());
}
function ViewParam(pg){
  if(!pg || !pg.p)
    return;

  var oscs=pg.p.length;
  document.getElementById("oscs").selectedIndex=oscs-1;

  var o=document.getElementById("prog2").firstChild;
  while(o=o.nextSibling){
    if(o.firstChild)
      o.firstChild.disabled=(oscs>=2)?false:true;
  }
  o=document.getElementById("prog3").firstChild;
  while(o=o.nextSibling){
    if(o.firstChild)
      o.firstChild.disabled=(oscs>=3)?false:true;
  }
  o=document.getElementById("prog4").firstChild;
  while(o=o.nextSibling){
    if(o.firstChild)
      o.firstChild.disabled=(oscs>=4)?false:true;
  }
  for(var i=0;i<oscs;++i){
    document.getElementById("g"+(i+1)).value=pg.p[i].g;
    document.getElementById("w"+(i+1)).value=pg.p[i].w;
    document.getElementById("v"+(i+1)).value=pg.p[i].v;
    document.getElementById("t"+(i+1)).value=pg.p[i].t;
    document.getElementById("f"+(i+1)).value=pg.p[i].f;
    document.getElementById("a"+(i+1)).value=pg.p[i].a;
    document.getElementById("h"+(i+1)).value=pg.p[i].h;
    document.getElementById("d"+(i+1)).value=pg.p[i].d;
    document.getElementById("s"+(i+1)).value=pg.p[i].s;
    document.getElementById("r"+(i+1)).value=pg.p[i].r;
    document.getElementById("p"+(i+1)).value=pg.p[i].p;
    document.getElementById("q"+(i+1)).value=pg.p[i].q;
    document.getElementById("k"+(i+1)).value=pg.p[i].k;
  }
  ViewDef(pg);
}
function OctChange(o){
  curOct=o;
}
function ProgChange(){
  let prog_name = "";

  if(9 == curCh){
    prog_name = synth.getProgNameGM(1, curNote-35);
    if(prog_name){
      document.getElementById("prog_num").value = curNote;
      document.getElementById("prog_name").innerHTML = prog_name;
      document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + curNote + "] " + prog_name;
    }else{
      document.getElementById("prog_num").value = curNote;
      document.getElementById("prog_name").innerHTML ="undefined";
      document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
      return;
    }
  }else{
    if("GM" == standMidi){
      prog_name = synth.getProgNameGM(0, curProg);
      if(prog_name){
        document.getElementById("prog_num").value = curProg;
        document.getElementById("prog_name").innerHTML = prog_name;
        document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + curProg + "] " + prog_name;
      }else{
        document.getElementById("prog_num").value = curProg;
        document.getElementById("prog_name").innerHTML ="undefined";
        document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
        return;
      }
    }else{
      let itemsBanks = document.getElementById("banks").childNodes;
      itemsBanks.forEach(function(item, index){
        if(item.innerHTML == curBank){
          item.style.backgroundColor = "#E3E3E3";
        }else{
          item.style.backgroundColor = "white";
        }
      });

      prog_name = synth.getProgNameSF(curBank, curProg);
      if(prog_name){
        document.getElementById("prog_num").value = curNote;
        document.getElementById("prog_name").innerHTML = prog_name;
        document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor of program[" + curNote + "] " + prog_name;
        document.getElementById("Preset_th1").innerHTML = " Preset "+curProg;

        let itemsPresets = document.getElementById("presets").childNodes;
        itemsPresets.forEach(function(item, index){
          let itm = item.firstChild;
          let itmIdx = item.lastChild;
          if(itm.innerHTML == prog_name){
            item.style.backgroundColor = "#E3E3E3";
            getInfoPrmSF('presets',prog_name,itmIdx.innerHTML, 'presets');
            document.getElementById("presets").scrollTop = 14 * index;
          }else{
            item.style.backgroundColor = "white";
          }
        });
      }else{
        document.getElementById("prog_num").value = curNote;
        document.getElementById("prog_name").innerHTML ="undefined";
        document.getElementById("head_soundeditorGM").innerHTML = "Timbre Editor";
        return;
      }
    }
  }

  if(synth){
    let pg;
    synth.send([0xc0+curCh,curProg]);
    if(9 != curCh){
      pg=synth.program[curProg];
    }else{
      pg=synth.drummap[curNote];
    }
    ViewParam(pg);
  }
}
function SetQuality(n){
  var pg;
  synth.quality=n;
  if(curCh==9)
    pg=synth.drummap[curNote];
  else
    pg=synth.program[curProg];
  ViewParam(pg);
}
function GetVal(id){
  var s=+document.getElementById(id).value;
  if(isNaN(s))
    s=0;
  return s;
}
function OpenKbd(){
  var kbd = document.getElementById("kbd");

  if( "none" == kbd.style.display) {
    kbd.style.display = "block";
  }else{
    kbd.style.display = "none";
  }
}
function saveSettings(){
  var masterAPIkey = document.getElementById("masterAPIkey");
  var soundFontsGS = document.querySelector("#tblSoundFontsGS tbody");
  var soundFontsXG = document.querySelector("#tblSoundFontsXG tbody");

  if (soundFontsGS) localStorage.setItem("soundFontsGS", soundFontsGS.innerHTML);

  if (soundFontsXG) localStorage.setItem("soundFontsXG", soundFontsXG.innerHTML);

  localStorage.setItem("masterAPIkey", masterAPIkey.value);

  checkStandardSF();
}
function openAbout(id){
  var stave = document.getElementById("stave");

  stave.className = "staveAbout";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_about").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    let lbl1 = document.createElement("label");
    lbl1.innerHTML = "The developer of the <a href='https://wordpress.org/plugins/midi-synth/' target='_blank'>midi-Synth</a> synthesizer plugin uses third-party modules with his own modifications:";
    stave.appendChild(lbl1);

    let lbl2 = document.createElement("label");
    lbl2.innerHTML = "1. Controls on the front panel of the synthesizer <a href='https://g200kg.github.io/webaudio-controls/docs/detailspecs.html' target='_blank'>webaudio-controls</a>"
    stave.appendChild(lbl2);

    let lbl3 = document.createElement("label");
    lbl3.innerHTML = "2. Midi synthesizer core with a GM tone map <a href='https://g200kg.github.io/webaudio-tinysynth/soundedit.html' target='_blank'>WebAudio-TinySynth</a>"
    stave.appendChild(lbl3);

    let lbl4 = document.createElement("label");
    lbl4.innerHTML = "3. Access to online-convert.com computing resources through their API <a href='https://audio.online-convert.com/' target='_blank'>api2convert.com</a>"
    stave.appendChild(lbl4);

    let lbl5 = document.createElement("label");
    lbl5.innerHTML = "4. Software for write midi files <a href='https://github.com/jazz-soft/JZZ-midi-SMF' target='_blank'>JZZ-midi-SMF</a>"
    stave.appendChild(lbl5);

    let lbl6 = document.createElement("label");
    lbl6.innerHTML = "5. Software for reading and check MIDI files structure <a href='https://github.com/nfroidure/midifile' target='_blank'>midifile</a>"
    stave.appendChild(lbl6);

    let lbl7 = document.createElement("label");
    lbl7.innerHTML = "6. Software for reading and check SoundFonts files structure <a href='https://github.com/Mrtenz/soundfont2' target='_blank'>soundfont2</a>"
    stave.appendChild(lbl7);

    let lbl8 = document.createElement("label");
    lbl8.innerHTML = "7. Software for rendering music notation <a href='https://www.vexflow.com' target='_blank'>VexFlow</a>"
    stave.appendChild(lbl8);

    let lbl9 = document.createElement("label");
    lbl9.innerHTML = "8. Software for play soundfonts (sf2 files) <a href='https://github.com/felixroos/sfumato' target='_blank'>sfumato</a>"
    stave.appendChild(lbl9);

    let lbl10 = document.createElement("label");
    lbl10.innerHTML = "9. You can send comments and suggestions regarding the <a href='https://adminkov.bcr.by/midi/' target='_blank'>midi-Synth</a> plugin to the address: klenitskiy.oleg@mail.ru"
    stave.appendChild(lbl10);
  }
}
function openExamples(id){
  let tbl = document.createElement("table");
  let tr;
  let th;
  let td;

  stave.className = "staveExamples";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
  }else{
    document.getElementById("btn_examples").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    tbl.id = "midi_examples";

    tr = document.createElement("tr");
    th = document.createElement("th");
    th.innerHTML = "Tools";
    tr.appendChild(th);
    th = document.createElement("th");
    th.innerHTML = "Description";
    tr.appendChild(th);
    th = document.createElement("th");
    th.innerHTML = "Upload";
    tr.appendChild(th);
    tbl.appendChild(tr);

    let btn1 = document.createElement("button");
    btn1.className = "btn_sequencer";
    btn1.setAttribute("style", "height:20px;");
    btn1.innerText = "midi 1";
    btn1.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "velocity.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"velocity.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Velocity";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Velocity and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn1);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn2 = document.createElement("button");
    btn2.className = "btn_sequencer";
    btn2.setAttribute("style", "height:20px;");
    btn2.innerText = "midi 2";
    btn2.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "volume.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"volume.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Volume";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Volume and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn2);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn3 = document.createElement("button");
    btn3.className = "btn_sequencer";
    btn3.setAttribute("style", "height:20px;");
    btn3.innerText = "midi 3";
    btn3.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "pitchbend.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"pitchbend.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "PitchBend";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description PitchBend and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn3);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn4 = document.createElement("button");
    btn4.className = "btn_sequencer";
    btn4.setAttribute("style", "height:20px;");
    btn4.innerText = "midi 4";
    btn4.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "panpos.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"panpos.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Panpos";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Panpos and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn4);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn5 = document.createElement("button");
    btn5.className = "btn_sequencer";
    btn5.setAttribute("style", "height:20px;");
    btn5.innerText = "midi 5";
    btn5.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "expression.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"expression.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Expression";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Expression and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn5);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn6 = document.createElement("button");
    btn6.className = "btn_sequencer";
    btn6.setAttribute("style", "height:20px;");
    btn6.innerText = "midi 6";
    btn6.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "modulation.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"modulation.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Modulation";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Modulation and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn6);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn7 = document.createElement("button");
    btn7.className = "btn_sequencer";
    btn7.setAttribute("style", "height:20px;");
    btn7.innerText = "midi 7";
    btn7.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "softpedal.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"softpedal.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "SoftPedal";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description SoftPedal and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn7);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn8 = document.createElement("button");
    btn8.className = "btn_sequencer";
    btn8.setAttribute("style", "height:20px;");
    btn8.innerText = "midi 8";
    btn8.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "sostenuto.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"sostenuto.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Sostenuto";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Sostenuto and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn8);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn9 = document.createElement("button");
    btn9.className = "btn_sequencer";
    btn9.setAttribute("style", "height:20px;");
    btn9.innerText = "midi 9";
    btn9.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "sustain.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"sustain.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Sustain";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Sustain and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn9);
    tr.appendChild(td);
    tbl.appendChild(tr);

    let btn10 = document.createElement("button");
    btn10.className = "btn_sequencer";
    btn10.setAttribute("style", "height:20px;");
    btn10.innerText = "midi 10";
    btn10.addEventListener("click",function(e){
      initArrTools();
      document.getElementById("file_name_midi").value = "balance.mid";
      document.getElementById("file_size_midi").value = "139 bytes";
      synth.loadMIDIUrl(midiSynth_url_files+"balance.mid");
    });
    tr = document.createElement("tr");
    td = document.createElement("td");
    td.innerHTML = "Balance";
    td.setAttribute("style", "width:16%;padding-left:5px;");
    tr.appendChild(td);
    td = document.createElement("td");
    td.innerHTML = "Description Balance and upload to synthesizer";
    tr.appendChild(td);
    td = document.createElement("td");
    td.setAttribute("style", "width:10%;text-align:center;");
    td.appendChild(btn10);
    tr.appendChild(td);
    tbl.appendChild(tr);

    stave.appendChild(tbl);
  }
}
function openRules(id){
  var stave = document.getElementById("stave");

  stave.className = "staveRules";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_rules").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    //loader on
    let loader4 = document.createElement("div");
    loader4.className = "loader4";
    document.getElementById("stave").appendChild(loader4);

    //Get .png images of rules from server.
    var xhr = new XMLHttpRequest();
    var formData = new FormData();

    formData.append("action", "rulesImgs");
    formData.append("nonce", midiSynth_nonce);

    xhr.open("POST", midiSynth_url_ajax);
    xhr.send(formData);

    xhr.onreadystatechange = function(){
      if (this.readyState == 4 && this.status == 200) {
        let loader4 = document.getElementsByClassName("loader4");
        if(undefined !== loader4[0]) document.getElementById("stave").removeChild(loader4[0]);

        let result = this.response.split("|");
        for(let i=0; i <= result.length; i += 2){
          let blockHead = document.createElement("div");
          blockHead.setAttribute("style", "display:flex;justify-content: space-around;width:100%;margin-bottom:10px");

          let correctHead = document.createElement("p");
          correctHead.innerHTML = "correct";
          correctHead.setAttribute("style", "width:50%;padding:0;margin:0;text-align: center;");
          blockHead.appendChild(correctHead);

          let wrongHead = document.createElement("p");
          wrongHead.innerHTML = "wrong";
          wrongHead.setAttribute("style", "width:50%;padding:0;margin:0;text-align: center;");
          blockHead.appendChild(wrongHead);

          if(result[i] && result[i+1]) stave.appendChild(blockHead);

          let blockImgs = document.createElement("div");
          blockImgs.setAttribute("style", "display:flex;justify-content: space-around;width:100%;margin-bottom:20px;");

          if(result[i] && result[i+1]) blockImgs.innerHTML = result[i]+result[i+1];

          stave.appendChild(blockImgs);
        }
      }
    };
    xhr.onerror = function(){
      console.log(this.responseText);
      return "";
    };

  }
}
function openErrors(id){
  var stave = document.getElementById("stave");

  stave.className = "staveErrors";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_errors").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    if("" == selTrackNum && 0 == errMidi.length){
      document.getElementById("ptrTimeStave").style.display = "none";
      document.getElementById("btnsStave").style.display = "none";
      stave.className = "noSelectedTrack";
      let msg = document.createElement("label");
      msg.innerHTML = "no selected track";
      msg.setAttribute("style", "display:block;width:100%;font-size:22px;font-weight: bold;color:red;text-align:center;");
      stave.appendChild(msg);
    }else{
      stave.className = "staveErrors";
      drawBadNotes();
    }
  }
}
/**
 * [drawBadNotes description]
 * @return {[type]} [description]
 */
function drawBadNotes(){
  let strHead = document.createElement("p");
  strHead.innerHTML = "MIDI Stave errors:";
  strHead.id = "err_midi";
  strHead.setAttribute("style","margin:0;font-weight:bold;font-size:14px;width:100%;height:20px;");

  stave.innerHTML = "";
  stave.appendChild(strHead);

  if(0 == arrBadNotes.length && 0 == errMidi.length){
    stave.innerHTML = "no errors";
  }else{
    if(0 !== errMidi.length){
      errMidi.forEach(function(item, index){
        let str = document.createElement("p");
        str.setAttribute("style", "width:100%;margin:0;");
        str.innerHTML = item;
        stave.appendChild(str);
      });
    }

    let uniqueBadNotes = [...new Set(arrBadNotes)];
    uniqueBadNotes.forEach(function(item, index){
      let str = document.createElement("div");
      str.setAttribute("style", "display:flex;font-size:13px;color:black;width:100%;");
      let p1 = document.createElement("p");
      p1.setAttribute("style", "width:100px;margin:0;");
      let p2 = document.createElement("p");
      p2.setAttribute("style", "width:630px;margin:0;");

      p1.innerHTML = "Measure: "+parseInt(item[0]+1);
      p2.innerHTML = "Notes: "+item[1];

      str.appendChild(p1); str.appendChild(p2);

      stave.appendChild(str);
    });
  }
}
/**
 * Get names of soundFontsXG from server
 *
 * @return {[type]} [description]
 */
function getSoundFontsAttrs(standard){
  var xhr = new XMLHttpRequest();
  var formData = new FormData();

  formData.append("action", "soundFonts"+standard);
  formData.append("nonce", midiSynth_nonce);

  xhr.open("POST", midiSynth_url_ajax);
  xhr.send(formData);

  xhr.onreadystatechange = function(){
    if (this.readyState == 4 && this.status == 200) {
      let result = this.responseText.replaceAll('&quot;', '"');
      result = JSON.parse(result);
      //Create tbl Sound Fonts GS, XG
      tblSoundFonts(result,standard);
    }
  };
  xhr.onerror = function(){
    console.log(this.responseText);
    return "";
  };
}
function formatBytes(bytes, decimals = 2){
  if (bytes === 0) return '0 Bytes';

  const k = 1024;
  const dm = decimals < 0 ? 0 : decimals;
  const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];

  const i = Math.floor(Math.log(bytes) / Math.log(k));

  var val = parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];

  return val;
}
/**
 * Helper function for the Settings section
 * @param  {[type]} standard [description]
 * @param  {[type]} index    [description]
 * @return {[type]}          [description]
 */
function selRowTbl(standard,index){
  document.getElementById(standard + index).click();
  let allradio  = document.querySelectorAll(`input[name=soundFonts${standard}]`);
  let myChecked = document.querySelector(`input[name=soundFonts${standard}]:checked`);

  Array.from(allradio).forEach(function(item, index){
    if(item.id == myChecked.id){
      item.setAttribute("checked", "");
    }else{
      item.removeAttribute("checked");
    }
  });
}
/**
 * Helper function for the Settings section
 * @param  {[type]} standard [description]
 * @param  {[type]} index    [description]
 * @return {[type]}          [description]
 */
function delRowTbl(standard,index){
  let idDel = standard + index;
  let rows;
  let tbodySF;

  if("GS" == standard){
    tbodySF = document.querySelector("#tblSoundFontsGS tbody");
  }
  if("XG" == standard){
    tbodySF = document.querySelector("#tblSoundFontsXG tbody");
  }

  rows = tbodySF.childNodes;

  Array.from(rows).forEach(function(item, index){
    let btnDel = item.querySelector(`#${idDel}`);
    if(btnDel) {
      tbodySF.removeChild(item);
      if("local" == item.cells[5].innerHTML){
        let fileName = item.cells[1].innerHTML;
        delLocalSoundFonts(fileName);
      }
    }
  });
}
/**
 * Create table SoundFontsGS, SoundFontsXG in settings
 * @param  {[type]} result [description]
 * @return {[type]}        [description]
 */
function tblSoundFonts(result,standard){
  let stave = document.getElementById("stave");
  let tblSoundFonts = document.createElement("table");

  tblSoundFonts.id = "tblSoundFonts" + standard;

  let thead  = document.createElement("thead");
  let tbody  = document.createElement("tbody");
  let tfoot  = document.createElement("tfoot");
  let tr;
  let th;
  let td;
  let input;

  tr = document.createElement("tr");

  th  = document.createElement("th");
  th.setAttribute("colspan", 5);
  th.innerHTML = "Sound Fonts " + standard ;

  tr.appendChild(th);
  thead.appendChild(tr);
  tblSoundFonts.appendChild(thead);

  Object.keys(result).forEach(function(item, index){
    // console.log("name:",result[item].name, "size:",formatBytes(result[item].size), "date:", result[item].lastmod);
    tr = document.createElement("tr");
    td  = document.createElement("td");
    input = document.createElement("input");

    // Get the last modified date string
    const lastModString = result[item].lastmod;
    // Create a Date object from the string
    const lastModDate = new Date(lastModString);
    // Format the date using toLocaleDateString()
    const formattedDate = lastModDate.toLocaleDateString();
    // You can also specify a locale and options for more control:
    const options = { year: 'numeric', month: 'short', day: 'numeric' };
    const formattedDateWithOptions = lastModDate.toLocaleDateString('en-US', options);

    input.setAttribute("style", "margin: 0 2px;cursor:pointer");
    input.setAttribute("type", "radio");
    input.setAttribute("name", "soundFonts"+standard);
    input.setAttribute("id", standard + index);
    input.setAttribute("value", result[item].name + "|"+formatBytes(result[item].size)+"|"+formattedDateWithOptions+"|remote");
    if("GS" == standard){
      input.setAttribute("onclick", `selRowTbl('GS',${index});`);
    }
    if("XG" == standard){
      input.setAttribute("onclick", `selRowTbl('XG',${index});`);
    }
    td.setAttribute("style", "padding:0;");
    td.setAttribute("width", "5%");
    td.appendChild(input);
    tr.appendChild(td);

    td  = document.createElement("td");
    td.setAttribute("style", "cursor:pointer;");

    if("GS" == standard){
      td.setAttribute("onclick", `selRowTbl('GS',${index});`);
    }
    if("XG" == standard){
      td.setAttribute("onclick", `selRowTbl('XG',${index});`);
    }

    td.innerHTML = result[item].name;
    td.setAttribute("width", "35%");
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = formatBytes(result[item].size);
    td.setAttribute("width", "19%");
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = formattedDateWithOptions;
    td.setAttribute("width", "19%");
    tr.appendChild(td);

    td  = document.createElement("td");
    input = document.createElement("input");
    input.value = "x";
    input.setAttribute("style", "padding:0;width:20px;background:white;color:black;");
    input.type = "button";
    input.id = "btn"+standard+index;
    input.title = "del row";

    if("GS" == standard){
      input.setAttribute("onclick", `delRowTbl('GS',${index});`);
    }
    if("XG" == standard){
      input.setAttribute("onclick", `delRowTbl('XG',${index});`);
    }

    td.setAttribute("width", "5%");
    td.setAttribute("style", "padding:0;");
    td.appendChild(input);
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = "remote";
    td.setAttribute("width", "12%");
    td.setAttribute("style", "padding:0;");
    tr.appendChild(td);
    tbody.appendChild(tr);
  });
  tblSoundFonts.appendChild(tbody);

  let th1 = document.createElement("th");
  th1.id = "add" + standard;
  th1.setAttribute("colspan", 2);
  th1.setAttribute("style", "cursor:pointer;");
  th1.innerHTML = "Add item";
  if("GS" == standard){
    th1.setAttribute("onclick", "loadPrivateSoundFonts('GS');");
  }
  if("XG" == standard){
    th1.setAttribute("onclick", "loadPrivateSoundFonts('XG');");
  }

  let th2 = document.createElement("th");
  th2.id = "clearTbl" + standard;
  th2.setAttribute("colspan", 2);
  th2.setAttribute("style", "cursor:pointer;");
  th2.innerHTML = "Clear tbl";
  if("GS" == standard){
    th2.setAttribute("onclick", "clearTblSoundFonts('GS');");
  }
  if("XG" == standard){
    th2.setAttribute("onclick", "clearTblSoundFonts('XG');");
  }

  tr = document.createElement("tr");
  tr.appendChild(th1); tr.appendChild(th2);
  tfoot.appendChild(tr);
  tblSoundFonts.appendChild(tfoot);

  let subDiv2 = document.getElementById("subDiv2");
  if("GS" == standard){
    let tblGS = document.getElementById("tblSoundFontsGS");
    if(tblGS) document.getElementById("subDiv2").removeChild(tblGS);
    subDiv2.prepend(tblSoundFonts);
  }
  if("XG" == standard){
    subDiv2.appendChild(tblSoundFonts);
  }

  //loader off
  if("GS" == standard){
    let loader1 = document.getElementsByClassName("loader1");
    if(undefined !== loader1[0]) stave.removeChild(loader1[0]);
  }
  if("XG" == standard){
    let loader2 = document.getElementsByClassName("loader2");
    if(undefined !== loader2[0]) stave.removeChild(loader2[0]);
  }
}
/**
 * Clear localStorage, SoundFontsDB
 * @param  {[type]} standard [description]
 * @return {[type]}          [description]
 */
function clearTblSoundFonts(standard){
  localStorage.removeItem("soundFontsGS");
  localStorage.removeItem("soundFontsXG");

  db.close();
  let deleteRequest = indexedDB.deleteDatabase(db.name);

  openSoundFontsDB();
  if("GS" == standard){
    let tblGS = document.getElementById("tblSoundFontsGS");
    tblGS.innerHTML = "";
    //loader on
    let loader = document.createElement("div");
    loader.className = "loader1";
    document.getElementById("stave").appendChild(loader);

    let tbodySoundFontsGS = localStorage.getItem("soundFontsGS");
    if("" == tbodySoundFontsGS || null == tbodySoundFontsGS) {
      getSoundFontsAttrs("GS");
    }else{
      tblSoundFonts({},"GS");
      document.querySelector("#tblSoundFontsGS tbody").innerHTML = tbodySoundFontsGS;
    }
  }
  if("XG" == standard){
    let tblXG = document.getElementById("tblSoundFontsXG");
    document.getElementById("subDiv2").removeChild(tblXG);
    //loader on
    let loader = document.createElement("div");
    loader.className = "loader2";
    document.getElementById("stave").appendChild(loader);

    let tbodySoundFontsXG = localStorage.getItem("soundFontsXG");
    if("" == tbodySoundFontsXG || null == tbodySoundFontsXG) {
      getSoundFontsAttrs("XG");
    }else{
      tblSoundFonts({},"XG");
      document.querySelector("#tblSoundFontsXG tbody").innerHTML = tbodySoundFontsXG;
    }
  }
}
/**
 * Load private SoundFonts (GS or XG standard)
 * @param  {[type]} standard GS or XG
 * @return {[type]}          [description]
 */
function loadPrivateSoundFonts(standard){
  let inputSoundFont = document.createElement("input");

  inputSoundFont.setAttribute("type", "file");
  inputSoundFont.setAttribute("accept", ".sf2");
  inputSoundFont.setAttribute("onchange", `showFile(this,'${standard}');`);
  inputSoundFont.setAttribute("style", "display:none;");
  inputSoundFont.setAttribute("multiple",true);

  inputSoundFont.click();
}
/**
 * Load list of SoundFont private ans add to prev list
 * @param  {[type]} input [description]
 * @return {[type]}       [description]
 */
async function showFile(inputFile,standard) {
  let files = inputFile.files;
  let tbodySF;
  let reader;

  if("GS" == standard){
    tbodySF = document.querySelector("#tblSoundFontsGS tbody");
  }
  if("XG" == standard){
    tbodySF = document.querySelector("#tblSoundFontsXG tbody");
  }

  let td;
  let tr;
  let input;
  let count = tbodySF.childNodes.length;

  Array.from(files).forEach(function(file, index){
    reader = new FileReader();
    reader.onload=async function(e){
      let content = e.target.result;
      await addLocalSoundFonts(file, content);
    }
    reader.onerror = function(e) {
      console.error(`Error reading file "${file.name}":`, e);
    };
    reader.readAsArrayBuffer(file);

    // Get the last modified date string
    const lastModString = file.lastModifiedDate;
    // Create a Date object from the string
    const lastModDate = new Date(lastModString);
    // Format the date using toLocaleDateString()
    const formattedDate = lastModDate.toLocaleDateString();
    // You can also specify a locale and options for more control:
    const options = { year: 'numeric', month: 'short', day: 'numeric' };
    const formattedDateWithOptions = lastModDate.toLocaleDateString('en-US', options);

    tr = document.createElement("tr");
    input = document.createElement("input");
    input.setAttribute("style", "margin: 0 2px;cursor:pointer");
    input.setAttribute("type", "radio");
    input.setAttribute("name", "soundFonts"+standard);
    input.setAttribute("id", standard + parseInt(count+index));
    input.setAttribute("value", file.name + "|"+formatBytes(file.size)+ "|"+formattedDateWithOptions+ "|local");
    if("GS" == standard){
      input.setAttribute("onclick", `selRowTbl('GS',${parseInt(count+index)});`);
    }
    if("XG" == standard){
      input.setAttribute("onclick", `selRowTbl('XG',${parseInt(count+index)});`);
    }

    td = document.createElement("td");
    td.setAttribute("style", "padding:0;");
    td.setAttribute("width", "5%");
    td.appendChild(input);
    tr.appendChild(td);

    td  = document.createElement("td");
    td.setAttribute("style", "cursor:pointer;");
    if("GS" == standard){
      td.setAttribute("onclick", `selRowTbl('GS',${parseInt(count+index)});`);
    }
    if("XG" == standard){
      td.setAttribute("onclick", `selRowTbl('XG',${parseInt(count+index)});`);
    }
    td.innerHTML = file.name;
    td.setAttribute("width", "35%");
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = formatBytes(file.size);
    td.setAttribute("width", "19%");
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = formattedDateWithOptions;
    td.setAttribute("width", "19%");
    tr.appendChild(td);

    td  = document.createElement("td");
    input = document.createElement("input");
    input.value = "x";
    input.setAttribute("style", "padding: 0;width: 20px;background:white;color: black;");
    input.type = "button";
    input.id = "btn"+standard+parseInt(index+count);
    input.title = "del row";

    if("GS" == standard){
      input.setAttribute("onclick", `delRowTbl('GS',${parseInt(count+index)});`);
    }
    if("XG" == standard){
      input.setAttribute("onclick", `delRowTbl('XG',${parseInt(count+index)});`);
    }

    td.setAttribute("width", "5%");
    td.setAttribute("style", "padding:0;");
    td.appendChild(input);
    tr.appendChild(td);

    td  = document.createElement("td");
    td.innerHTML = "local";
    td.setAttribute("width", "12%");
    td.setAttribute("style", "padding:0;");
    tr.appendChild(td);

    tbodySF.appendChild(tr);
  });
}
function openSetting(id){
  let stave = document.getElementById("stave");

  stave.className = "staveSetting";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_setting").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    let subDiv1 = document.createElement("div");
    subDiv1.id = "subDiv1";
    subDiv1.setAttribute("style", "display:flex;align-items: center;width:100%;height:25px;background:#C3C3C3;font-family: 'Arial, Helvetica, sans-serif';");

    let lblApi = document.createElement("label");
    lblApi.innerHTML = "Master API key: ";
    lblApi.setAttribute("style", "width:100px;");
    subDiv1.appendChild(lblApi);

    let input1 = document.createElement("input");
    input1.id = "masterAPIkey";
    input1.setAttribute("style", "width:250px;height: 25px;font-family: 'Arial, Helvetica, sans-serif';");
    input1.value = localStorage.getItem("masterAPIkey");
    subDiv1.appendChild(input1);

    let lblDescription = document.createElement("label");
    lblDescription.innerHTML = "Get key and insert it after registering on <a href='https://account.api2convert.com/user/apikeys' target='_blank'>api2convert.com</a> ";
    lblDescription.setAttribute("style", "width:340px;");
    subDiv1.appendChild(lblDescription);

    let btn = document.createElement("button");
    btn.id = "saveSettings";
    btn.setAttribute("title", "Save Settings");
    btn.className = "btn_sequencer";
    btn.setAttribute("style", "flex-basis: auto;align-self: flex-end;position:relative;top:5px;");
    btn.innerText = "Save Setting";
    btn.setAttribute("onclick", "saveSettings();");

    subDiv1.appendChild(btn);

    stave = document.getElementById("stave");
    stave.appendChild(subDiv1);

    let subDiv2 = document.createElement("div");
    subDiv2.id = "subDiv2";
    subDiv2.setAttribute("style", "display:flex;align-items: center;width:100%;height:100%;");
    stave.appendChild(subDiv2);

    //loader on
    let loader = document.createElement("div");
    loader.className = "loader1";
    document.getElementById("stave").appendChild(loader);

    let tbodySoundFontsGS = localStorage.getItem("soundFontsGS");
    if("" == tbodySoundFontsGS || null == tbodySoundFontsGS) {
      getSoundFontsAttrs("GS");
    }else{
      tblSoundFonts({},"GS");
      document.querySelector("#tblSoundFontsGS tbody").innerHTML = tbodySoundFontsGS;
    }

    //loader on
    loader = document.createElement("div");
    loader.className = "loader2";
    document.getElementById("stave").appendChild(loader);

    let tbodySoundFontsXG = localStorage.getItem("soundFontsXG");
    if("" == tbodySoundFontsXG || null == tbodySoundFontsXG) {
      getSoundFontsAttrs("XG");
    }else{
      tblSoundFonts({},"XG");
      document.querySelector("#tblSoundFontsXG tbody").innerHTML = tbodySoundFontsXG;
    }
  }
}
function openReport(id){
  var smf = createFileMidi();

  var stave = document.getElementById("stave");

  stave.className = "staveReport";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_report").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    stave.innerHTML = smf.toString();
  }
}
function openStave(id){
  var stave = document.getElementById("stave");

  stave.className = "staveStave";
  stave.innerHTML = "";
  btnTool = "";

  if(pressBtn == id){
    document.getElementById("ptrTimeStave").style.display = "none";
    document.getElementById("btnsStave").style.display = "none";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    document.getElementById("ptrTimeStave").style.display = "block";
    document.getElementById("btnsStave").style.display = "flex";

    stave.style.background = "#E3E3E3";
    document.getElementById("btn_stave").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    if("" == selTrackNum){
      document.getElementById("ptrTimeStave").style.display = "none";
      document.getElementById("btnsStave").style.display = "none";
      stave.className = "noSelectedTrack";
      let msg = document.createElement("label");
      msg.innerHTML = "no selected track";
      msg.setAttribute("style", "display:block;width:100%;font-size:22px;font-weight: bold;color:red;text-align:center;");
      stave.appendChild(msg);
    }else{
      stave.className = "staveStave";
      document.getElementById("ptrTimeStave").style.display = "block";
      btnsStave(clef);
    }
  }
}
function openTools(id){
  var stave = document.getElementById("stave");

  stave.className = "staveTools";
  stave.innerHTML = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_tools").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id)  pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    if("" == selTrackNum){
      let msg = document.createElement("label");
      msg.innerHTML = "no selected track";
      msg.setAttribute("style", "display:block;width:100%;font-size:22px;font-weight: bold;color:red;text-align:center;");
      stave.className = "noSelectedTrack";
      stave.appendChild(msg);
    }else{
      stave.className = "staveTools";
      let subDiv1 = document.createElement("div");
      subDiv1.id = "btns_tools";
      subDiv1.setAttribute("style", "display:flex;justify-content: space-around;height:30px;padding-left:37px;background:#C3C3C3;position: sticky;width: 100%;");

      let btn1 = document.createElement("button");
      btn1.id = "tool1";
      btn1.className = "btn_sequencer";
      btn1.innerText = "Velocity";
      btn1.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn1);

      let btn2 = document.createElement("button");
      btn2.id = "tool2";
      btn2.className = "btn_sequencer";
      btn2.innerText = "Volume";
      btn2.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn2);

      let btn3 = document.createElement("button");
      btn3.id = "tool3";
      btn3.className = "btn_sequencer";
      btn3.innerText = "Pitch Bend";
      btn3.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn3);

      let btn4 = document.createElement("button");
      btn4.id = "tool4";
      btn4.className = "btn_sequencer";
      btn4.innerText = "Panpos";
      btn4.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn4);

      let btn5 = document.createElement("button");
      btn5.id = "tool5";
      btn5.className = "btn_sequencer";
      btn5.innerText = "Expression";
      btn5.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn5);

      let btn6 = document.createElement("button");
      btn6.id = "tool6";
      btn6.className = "btn_sequencer";
      btn6.innerText = "Modulation";
      btn6.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn6);

      let btn7 = document.createElement("button");
      btn7.id = "tool7";
      btn7.className = "btn_sequencer";
      btn7.innerText = "SoftPedal";
      btn7.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn7);

      let btn8 = document.createElement("button");
      btn8.id = "tool8";
      btn8.className = "btn_sequencer";
      btn8.innerText = "Sostenuto";
      btn8.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn8);

      let btn9 = document.createElement("button");
      btn9.id = "tool9";
      btn9.className = "btn_sequencer";
      btn9.innerText = "Sustain";
      btn9.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn9);

      let btn10 = document.createElement("button");
      btn10.id = "tool10";
      btn10.className = "btn_sequencer";
      btn10.innerText = "Balance";
      btn10.setAttribute("onclick", "drawTools(id);");
      subDiv1.appendChild(btn10);

      let divTools = document.createElement("div");
      divTools.id = "divTools";
      divTools.setAttribute("style", "display:flex;height:156px;width: 100%;");

      let div_cnvTools = document.createElement("div");
      div_cnvTools.id = "div_cnvTools";
      div_cnvTools.setAttribute("style", "overflow-x:hidden;overflow-y:hidden;width:726px;");

      let cnvScaleTools = document.createElement("canvas");
      cnvScaleTools.id = "cnvScaleTools";
      cnvScaleTools.setAttribute("style", "display:block;height:152px;width:40px;background:#C3C3C3;");
      cnvScaleTools.setAttribute("height", 152);
      cnvScaleTools.setAttribute("width", 40);
      ctxScaleTools = cnvScaleTools.getContext("2d");

      let cnvTools = document.createElement("canvas");
      cnvTools.id = "cnvTools";
      cnvTools.setAttribute("style", "display:block;height:152px;background:#E3E3E3;cursor:crosshair;");
      cnvTools.setAttribute("height", 152);
      cnvTools.setAttribute("width", cnvScale.width);
      ctxTools = cnvTools.getContext("2d");

      cnvTools.removeEventListener("mousemove", updateArrDraft);
      cnvTools.addEventListener("mousemove", updateArrDraft);

      cnvTools.removeEventListener("mouseup", updateArrTool);
      cnvTools.addEventListener("mouseup", updateArrTool);

      cnvTools.removeEventListener("contextmenu", clearArrTool);
      cnvTools.addEventListener("contextmenu", clearArrTool);

      div_cnvTools.appendChild(cnvTools);
      divTools.appendChild(cnvScaleTools);
      divTools.appendChild(div_cnvTools);

      stave.appendChild(subDiv1);
      stave.appendChild(divTools);
    }
  }
}
/**
 * [openVerify description]
 * @param  {[type]} id [description]
 * @return {[type]}    [description]
 */
function openVerify(id){
  var stave = document.getElementById("stave");

  stave.className = "staveVerify";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_verify").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    //progressVerify on
    let progressVerify = document.createElement("div");
    progressVerify.className = "progress_main";
    progressVerify.id = "progress_main";

    let subDiv1 = document.createElement("div");
    subDiv1.className = "progress_child";
    progressVerify.appendChild(subDiv1);

    let subDiv2 = document.createElement("div");
    subDiv1.appendChild(subDiv2);

    let subSpan1 = document.createElement("span");
    subSpan1.className = "progress_value";
    progressVerify.appendChild(subSpan1);

    let subSpan2 = document.createElement("span");
    subSpan2.id = "process";
    subSpan2.innerHTML = "wait...";
    subSpan1.appendChild(subSpan2);

    document.getElementById("sequencer_subfooter2").appendChild(progressVerify);

    setTimeout(() => verifyNotes(), 100);
  }
}
function openHelp(id){
  var stave = document.getElementById("stave");

  stave.className = "staveHelp";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_help").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    viewHelp();
  }
}
function openExport(id){
  var stave = document.getElementById("stave");

  stave.className = "staveExport";
  stave.innerHTML = "";
  btnTool =

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "white";
    document.getElementById("btn_export").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    exportMid();
  }
}
function openRecord(id){
  var stave = document.getElementById("stave");

  stave.className = "staveRecord";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
    synth.setRecord(false);
    synth.stopMIDI();
  }else{
    stave.innerHTML = "";
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_record").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    if("" == selTrackNum){
      stave.className = "noSelectedTrack";
      let msg = document.createElement("label");
      msg.innerHTML = "no selected track";
      msg.setAttribute("style", "display:block;width:100%;font-size:22px;font-weight: bold;color:red;text-align:center;");
      stave.appendChild(msg);
    }else{
      stave.className = "staveRecord";
      let numCh = document.getElementById("part1_"+selTrackNum+"_ch").innerHTML;
      numCh = numCh.split(":");
      curCh = parseInt(numCh[1]-1);
      ch.value = numCh[1]; //Set ch.value on pannel Synth

      //Prepare midiSynth for record
      synth.setRecord(true);
      ptrTime.style.left = 0;
      subwin_part2.scrollLeft = 0;
      rec_cur_tick = 0;
      timerRecord();
      synth.playMIDI();
    }
  }
}
function openTrackInfo(id){
  var stave = document.getElementById("stave");

  let tbl = document.createElement("table");
  let program = [];
  let tr;
  let th;
  let td;

  stave.className = "staveTrack";
  stave.innerHTML = "";
  btnTool = "";

  document.getElementById("ptrTimeStave").style.display = "none";
  document.getElementById("btnsStave").style.display = "none";

  if(pressBtn == id){
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    pressBtn = "";
    stave.style.background = "#C3C3C3";
  }else{
    stave.style.background = "#E3E3E3";
    document.getElementById("btn_trackInfo").style.boxShadow =
    "inset -2px -2px 3px rgba(200, 200, 200, .6),inset 2px 2px 3px rgba(0, 0, 0, .6)";
    if(id) pressBtn = id;
    //Reset other btns
    document.getElementById("btn_verify").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_stave").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_tools").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_help").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_report").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_export").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_record").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_setting").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_about").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_examples").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_errors").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";
    document.getElementById("btn_rules").style.boxShadow =
    "inset 2px 2px 3px rgba(255, 255, 255, .6),inset -2px -2px 3px rgba(0, 0, 0, .6)";

    if("" == selTrackNum){
      stave.className = "noSelectedTrack";
      let msg = document.createElement("label");
      msg.innerHTML = "no selected track";
      msg.setAttribute("style", "display:block;width:100%;font-size:22px;font-weight: bold;color:red;text-align:center;");
      stave.appendChild(msg);
    }else{
      stave.className = "staveTrack";
      let idPart = "part1_"+ selTrackNum +"_ch";

      tbl.id = "track_info";

      tr = document.createElement("tr");

      th = document.createElement("th");
      th.innerHTML = "Name track";
      tr.appendChild(th);

      if("GM" == standMidi){
        if(9 == curCh){
          th = document.createElement("th");
          th.innerHTML = "Instruments (note: Name)";
          tr.appendChild(th);
        }else{
          th = document.createElement("th");
          th.innerHTML = "Instruments (prog: Num)";
          tr.appendChild(th);
        }
      }else{
        if(9 == curCh){
          th = document.createElement("th");
          th.innerHTML = "Instruments (note: Name)";
          tr.appendChild(th);
        }else{
          if(9 != curCh){
            th = document.createElement("th");
            th.innerHTML = "Banks";
            tr.appendChild(th);

            th = document.createElement("th");
            th.innerHTML = "Instrument [idx] preset";
            tr.appendChild(th);
          }
        }
      }

      th = document.createElement("th");
      th.innerHTML = "Channels available";
      tr.appendChild(th);

      th = document.createElement("th");
      th.innerHTML = "Measure / Notes";
      tr.appendChild(th);

      tbl.appendChild(tr);

      tr = document.createElement("tr");

      td = document.createElement("td");
      td.id = "info_name_track";
      td.style.width = "20%";                                           //Name track
      let nameTrk = document.createElement("input");
      let idTrackName = "part1_" + selTrackNum + "_trackName";
      nameTrk.value = document.getElementById(idTrackName).innerHTML;
      nameTrk.id = "infoNameTrk";
      nameTrk.setAttribute("style","text-align:center;width:100%;font-family: 'Arial, Helvetica, sans-serif';");
      nameTrk.addEventListener("input", function(){
        document.getElementById(idTrackName).innerHTML = nameTrk.value;
      });
      td.appendChild(nameTrk);
      tr.appendChild(td);
      //------------------------------------------------------------------
      if("GM" !== standMidi && 9 != curCh){
        td = document.createElement("td");                               //Bank
        td.setAttribute("style","text-align: center;width:10%;");
        td.innerHTML = "";

        let banks = document.createElement("select");
        banks.setAttribute("size", 6);
        banks.id = "banksTrackInfo";
        banks.setAttribute("style", "text-align: center;width:100%;color:black;")

        let bank;
        let banksSF = soundFont.banks;
        banksSF.forEach(function(item, index){
          bank = document.createElement("option");
          bank.id = "trkInfo_bank_"+index;
          bank.value = index;
          bank.innerHTML = index;
          bank.setAttribute("onclick", `getInfoPresets(${index})`);
          banks.appendChild(bank);
        });
        td.appendChild(banks);
        tr.appendChild(td);
      }

      td = document.createElement("td");                                //Instrument
      td.id = "info_track_instrument";
      let instruments = document.createElement("select");
      instruments.setAttribute("size", 6);
      instruments.id = "instruments";
      instruments.style.width = "100%";

      if("GM" == standMidi || 9 == curCh){
        td.style.width = "30%";
        td.setAttribute("style","text-align: center;padding: 3px;");
        let option1;

        if(9 == curCh){
          program = synth.drummap;
        }else{
          program = synth.program;
        }
        program.forEach(function(item, index){
          option1 = document.createElement("div");
          option1.setAttribute("style", "display:flex;width:100%;border:none;");
          option1.id = "option1_"+index;
          option1.value = index;

          let p1 = document.createElement("p");
          p1.setAttribute("style", "display:block;width:80%;margin:0;");
          if(9 !== curCh){
            p1.innerHTML = synth.getProgNameGM(0, index);
          }else{
            p1.innerHTML = synth.getProgNameGM(1, index);
          }

          let opt = document.createElement("option");
          opt.innerHTML = p2.innerHTML;
          opt.setAttribute("style", "display:block;width:20%;margin:0;");
          if(9 !== curCh){
            opt.innerHTML = index;
          }else{
            opt.innerHTML = synth.arrNotes[index+14];
          }
          option1.appendChild(p1); option1.appendChild(opt);

          if(9 !== curCh){
            let idInstrument = "";
            let progNum = "";
            idInstrument = "part1_" + selTrackNum + "_instr";
            progNum = document.getElementById(idInstrument).innerHTML.split(":");
            progNum = progNum[1].slice(0, -1);

            //get preset selectedIndex.
            instruments.selectedIndex = progNum;
            option1.setAttribute("onclick", `getInfoInstr('${idInstrument}','${p1.innerHTML}','${opt.innerHTML}')`);
          }

          instruments.appendChild(option1);
        });
      }else{
        td.style.width = "25%";                                         //Instrument
        td.setAttribute("style","padding: 3px;");
      }

      td.appendChild(instruments);
      tr.appendChild(td);

      //------------------------------------------------------------------
      td = document.createElement("td");
      td.id = "info_track_channel";
      td.style.width = "20%";                                             //Channel
      let channels = document.createElement("select");
      channels.setAttribute("size", 6);
      channels.id = "channels";
      channels.style.width = "100%";

      let idChannel = "part1_" + selTrackNum + "_ch";
      let chOld = document.getElementById(idChannel).innerHTML.split(":");
      chOld = chOld[1].trim();

      let option2;
      let freeChannels = synth.getChannelsFree();
      freeChannels.forEach(function(item, index){
        option2 = document.createElement("option");
        option2.id = "option2_"+index;
        option2.value = index;
        option2.innerHTML = "channel number:" + parseInt(item+1);
        let idInstrument = "part1_" + selTrackNum + "_ch";
        let channel = document.getElementById(idInstrument);
        option2.addEventListener("click", function(){
          let chNew = channels.options[channels.selectedIndex].text.split(":");
          chNew = chNew[1].trim();
          channel.innerHTML = "Channel:" + chNew;
          //Update channelsFree.
          synth.updateChannelsFree(chOld, chNew);
          if(10 == chNew) document.getElementById("part1_" + selTrackNum + "_instr").innerHTML = "Standard Drum Kit";
        });
        channels.appendChild(option2);
      });
      td.appendChild(channels);
      tr.appendChild(td);
      //-------------------------------------------------------------------
      td = document.createElement("td");
      td.style.width = "20%";                                              //measure_notes

      let measure_notes = document.createElement("select");
      measure_notes.setAttribute("size", 6);
      measure_notes.id = "info_track_measure_notes";
      measure_notes.style.width = "100%";

      let option3;
      let count = 0;
      arrVexFlow.forEach(function(item, index){
        option3 = document.createElement("option");
        option3.id = "option3_"+index;
        option3.value = index;

        let measure = item[0];
        let notes = item[1].split(",");
        notes.forEach(function(itm, idx){
          if(-1 !== itm.indexOf(" ")){
            let sub_itm = itm.split(" ");
            count += sub_itm.length;
          }else{
            count += 1;
          }
        });
        option3.innerHTML += "&nbsp;measure:"+parseInt(measure+1)+"&nbsp;"+"&nbsp; notes:"+count+"<br>";
        count = 0;
        measure_notes.appendChild(option3);
      });
      td.appendChild(measure_notes);
      tr.appendChild(td);

      tbl.appendChild(tr);
      stave.appendChild(tbl);

      if("GM" !== standMidi && 9 != curCh){
        let banks = document.getElementById("banksTrackInfo").childNodes;
        let selIndexBank = 0;
        for(let i=0; i < banks.length; i++){
          if(banks[i].value == curBank){
            selIndexBank = i;
            break;
          }
        }
        document.getElementById("banksTrackInfo").selectedIndex = selIndexBank;
        getInfoPresets(curBank);

        let instruments = document.getElementById("instruments").childNodes;
        let selIndexInstr = 0;
        for(let i=0; i < instruments.length; i++){
          let instr = instruments[i].lastChild.innerHTML;
          instr = instr.split(" ");
          instr = parseInt(instr[1]);
          if(instr == curProg){
            selIndexInstr = i;
            break;
          }
        }
        document.getElementById("instruments").selectedIndex = selIndexInstr;
      }
    }
  }
}
function getInfoPresets(selIndex){
  let obj = soundFont.banks;
  let program = obj[selIndex].presets.filter(element => element !== null);
  let option1;

  instruments.innerHTML = "";
  curBank = selIndex;

  program.forEach(function(item, index){
    option1 = document.createElement("div");
    option1.setAttribute("style", "display:flex;width:100%;border:none;");
    option1.id = "option1_"+index;
    option1.value = index;

    let p1 = document.createElement("p");
    p1.setAttribute("style", "display:block;width:70%;margin:0;color:black;");
    p1.innerHTML = item.header.name;

    let opt = document.createElement("option");
    opt.innerHTML = p2.innerHTML;
    opt.setAttribute("style", "display:block;width:30%;margin:0;color:black;");
    if(9 !== curCh){
      opt.innerHTML = "["+index+"] "+item.header.preset;
    }else{
      opt.innerHTML = item.header.preset;
    }
    option1.appendChild(p1); option1.appendChild(opt);

    let idInstrument = "";
    let progNum = "";
    idInstrument = "part1_" + selTrackNum + "_instr";

    //get preset selectedIndex.
    option1.setAttribute("onclick", `getInfoInstr('${idInstrument}','${p1.innerHTML}','${opt.innerHTML}')`);

    instruments.appendChild(option1);
  });
}
function getInfoInstr(idInstrument, prm1, prm2){
  let instruments = document.getElementById("instruments").childNodes;

  if("GM" == standMidi){
    document.getElementById(idInstrument).innerHTML = prm1 + " (prog:" +prm2+ ")";
    document.getElementById("instruments").selectedIndex = prm2;
  }else{
    let selIndexInstr = 0;
    for(let i=0; i < instruments.length; i++){
      if(instruments[i].value == curProg){
        selIndexInstr = i;
        break;
      }
    }
    let numId = idInstrument.slice(0, -5);
    document.getElementById(idInstrument).innerHTML = prm1;
    document.getElementById(numId+"elemBank").innerHTML = "bank:"+curBank;

    prm2 = prm2.split(" ");

    document.getElementById(numId+"elemPreset").innerHTML = "preset:"+prm2[1];
    prm2[0] = prm2[0].replace(/\[|\]/g, '');
    document.getElementById("instruments").selectedIndex = prm2[0];
  }
}
/**
 * Open Tembre Editor
 */
function OpenEditor(){
  var win_edit = document.getElementById("win_edit");

  if("none" == win_edit.style.display) {
    win_edit.style.display = "flex";
  }else{
    win_edit.style.display = "none";
  }
}
/**
 * Open Graph AudioNodes
 */
function OpenGraph(){
  var audiograph = document.getElementById("audiograph");

  //imgs
  document.getElementById("canvas_imgs").style.display = "none";

  if("GM" !== standMidi && 9 !== curCh) drawMetaDataSF2();

  if("none" == audiograph.style.display) {
    audiograph.style.display = "block";
  }else{
    audiograph_node_click = 0;
    audiograph.style.display = "none";
  }
}
function winSequencer(){
  var win_sequencer = document.getElementById("win_sequencer");

  if(undefined == synth.getMidiSrc())return;

  if ("flex" == win_sequencer.style.display) {
    win_sequencer.style.display = "none";
    selTrackNum = "";
  }else{
    win_sequencer.style.display = "flex";
    Sequencer();
  }
}
function Sequencer(){
  if(!synth) return;
  var srcMidi  = synth.getMidiSrc();
  var win_part1 = document.getElementById("win_part1");
  var standard = document.getElementById("standardMidi").querySelector(`webaudio-switch[name=standard][value='1']`);
  var typeMidi = synth.getTypeMidi();
  var tracksCount = 0;

  standard = standard.id;

  midiFile = new MIDIFile(srcMidi);

  if(0 == typeMidi){
    tracksCount = getTracksInfo().length;
  }else if(1 == typeMidi){
    tracksCount = midiFile.header.getTracksCount();
  }

  win_part1.innerHTML = "";

  for(let i=1; i < tracksCount; ++i ) {
    let div_rec = document.createElement("div");
    let sub_div1 = document.createElement("div");
    let sub_div2 = document.createElement("div");

    div_rec.id  = "part1_" + i;
    div_rec.setAttribute("onclick", `selTrack(${i});`);
    div_rec.style.width  = win_part1.style.width - 10;
    div_rec.setAttribute("style", "display:flex;flex-direction: column;align-items: flex-start;margin-left: 2px;padding-left:2px;font-size:12px;color:black;height:59px;background:#C1C1C1;border:1px solid black;margin-top:1px;");

    let trackName = document.createElement("div");
    trackName.setAttribute("style", "display:flex;width:100%;");

    let element = document.createElement("label");
    element.innerHTML = "Track no name";
    element.id = "part1_" + i + "_trackName";
    element.type = "text";
    element.placeholder  ="Name track";
    trackName.appendChild(element);

    if("GM" == standMidi){
      element.setAttribute("style", "font-size:12px;color:black;width:100%;height:18px;cursor:pointer;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;");
    }else{
      element.setAttribute("style", "font-size:12px;color:black;width:40%;height:18px;cursor:pointer;white-space: nowrap;overflow: hidden;text-overflow: ellipsis;");
    }
      let elemBank = document.createElement("label");
      elemBank.innerHTML = "bank:0";
      elemBank.id = "part1_" + i + "_elemBank";
      elemBank.setAttribute("style", "font-size:12px;color:black;width:28%;height:18px;cursor:pointer;");
      trackName.appendChild(elemBank);
      if("GM" == standMidi){
        elemBank.style.visibility = "hidden";
      }else{
        elemBank.style.visibility = "visible";
      }
      let elemPreset = document.createElement("label");
      elemPreset.innerHTML = "preset:0";
      elemPreset.id = "part1_" + i + "_elemPreset";
      elemPreset.setAttribute("style", "font-size:12px;color:black;width:28%;height:18px;cursor:pointer;");
      trackName.appendChild(elemPreset);
      if("GM" == standMidi){
        elemPreset.style.visibility = "hidden";
      }else{
        elemPreset.style.visibility = "visible";
      }

    div_rec.appendChild(trackName);

    sub_div1.setAttribute("style", "display:flex;flex-direction: row;align-items:center;justify-content: space-between;width:100%;");

    element = document.createElement("label");
    element.id = "part1_" + i + "_instr";
    element.innerHTML = "Instrument: ";
    element.setAttribute("style", "font-size:12px;color:black;width:100%;height:18px;cursor:pointer;white-space: nowrap;");
    sub_div1.appendChild(element);

    let img0 = new Image(32, 32);
    img0.src = speaker.src;
    img0.setAttribute("id","speaker_" + i);
    img0.setAttribute("onclick","speaker_on_off(id);");
    img0.setAttribute("width",32);
    img0.setAttribute("height",32);
    img0.setAttribute("class","speakers");
    img0.setAttribute("style","display:block;width:16px;height:16px;cursor:pointer;");
    sub_div1.appendChild(img0);

    let img1 = new Image(32, 32);
    img1.src = speaker_on.src;
    img1.setAttribute("id","speakerOn_" + i);
    img1.setAttribute("onclick","speaker_on_off(id);");
    img1.setAttribute("width",32);
    img1.setAttribute("height",32);
    img1.setAttribute("class","speakers");
    img1.setAttribute("style","display:none;width:16px;height:16px;cursor:pointer;");
    sub_div1.appendChild(img1);

    let img2 = new Image(32, 32);
    img2.src = speaker_off.src;
    img2.setAttribute("id","speakerOff_" + i);
    img2.setAttribute("onclick","speaker_on_off(id);");
    img2.setAttribute("width",32);
    img2.setAttribute("height",32);
    img2.setAttribute("class","speakers");
    img2.setAttribute("style","display:none;width:16px;height:16px;cursor:pointer;");
    sub_div1.appendChild(img2);

    div_rec.appendChild(sub_div1);

    sub_div2.setAttribute("class", "sub_div_part1");
    sub_div2.id  = "sub_div_" + i;
    sub_div2.setAttribute("style", "display:flex;flex-direction: row;align-items:center;justify-content: space-between;width:100%;");

    element = document.createElement("label");
    element.id = "part1_"+i+"_ch";
    element.className = "lbl_ch";
    element.innerHTML = "Channel:";
    element.setAttribute("style", "width:75px;");
    sub_div2.appendChild(element);

    element = document.createElement("label");
    element.className = "lbl_ch";
    element.innerHTML = "Vol:";
    element.setAttribute("style", "width:20px;margin-left:5px;");
    sub_div2.appendChild(element);

    element = document.createElement("input");
    element.id="part1_"+i+"_vol";
    element.type = "range";
    element.min = "0";
    element.max = "127";
    element.value = "64";
    element.className = "slider_ch";
    element.setAttribute("onclick","sliders_vol(id);");
    sub_div2.appendChild(element);

    element = document.createElement("label");
    element.className = "lbl_ch";
    element.innerHTML = "Pan:";
    element.setAttribute("style", "width:25px;margin-left:5px;");
    sub_div2.appendChild(element);

    element = document.createElement("input");
    element.id="part1_"+i+"_pan";
    element.type = "range";
    element.min = "0";
    element.max = "127";
    element.value = "64";
    element.className = "slider_ch";
    element.setAttribute("style", "margin-right:5px;");
    element.setAttribute("onclick","sliders_pan(id);");
    sub_div2.appendChild(element);

    div_rec.appendChild(sub_div2);

    win_part1.appendChild(div_rec);
  }

  drawRangeNotes();
  drawHeaderInfo();
  drawTrackInfo();
  drawNotesStrip();
  drawTimeScale();
  drawNotesSong();

  let div_rangeNotes_part2 = document.getElementById("div_rangeNotes_part2");
  subwin_part2.addEventListener("scroll", () => {
    div_rangeNotes_part2.scrollTop = subwin_part2.scrollTop;

    let stave = document.getElementById("stave");
    let div_cnvTools = document.getElementById("div_cnvTools");
    if(div_cnvTools && "none" !== stave.style.display){
      div_cnvTools.scrollLeft = subwin_part2.scrollLeft;
    }
  });

  //Restore previous values
  subwin_part2.scrollTop = changedDataParams.scrollTop;
  subwin_part2.scrollLeft = changedDataParams.scrollLeft;
  if(changedDataParams.selTrackId)selTrack(changedDataParams.selTrackId);
}
function SequencerScale(){
  //imgs for Graph
  document.getElementById("canvas_imgs").style.display = "none";

  if(synth){
    if (true == synth.playing) {
      document.getElementById("scale").setAttribute("style","pointer-events:none;opacity:0.9;background-color: #f2f2f2;color: #999;cursor:not-allowed;position:absolute;display:flex;justify-content: space-evenly;align-items: center;height:14px;width:40px;overflow: hidden;font-weight:bold;font-size:14px;top:-14px;left:208px;border: 1px solid black;background:#C3C3C3;");
    }else{
      document.getElementById("scale").setAttribute("style","pointer-events:auto;opacity:1;background-color:transparent;color:black;cursor:pointer;position:absolute;display:flex;justify-content: space-evenly;align-items: center;height:14px;width:40px;overflow: hidden;font-weight:bold;font-size:14px;top:-14px;left:208px;border: 1px solid black;background:#C3C3C3;");
    }
  }
}
function Sustain(b){
  synth.send([0xb0+curCh,64,b?127:0]);
}
/**
 * Check position mouse on audiograph canvas.
 * @return {[type]} [description]
 */
function audiograph_check_pos(e){
  let audiograph = document.getElementById("audiograph");
  let ctx = audiograph.getContext("2d");

  audiograph.style.cursor = "default";
  audiograph_node = "";

  let mouseX = e.offsetX;
  let mouseY = e.offsetY;

  let nodeName = Nodes_pos.node;
  let nodeXY;
  let nodeX;
  let nodeY;

  for (let i = 0; i < Nodes_pos.length; i++) {
    nodeName = Nodes_pos[i].node.split(" ");
    nodeXY   = Nodes_pos[i].posXY.split(",");
    nodeX    = parseInt(nodeXY[0]);
    nodeY    = parseInt(nodeXY[1]);

    switch(nodeName[0]) {
      case "GainNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.GainNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.GainNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = Nodes_pos[i].node;
        }
        break;
      case "OscillatorNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.OscillatorNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.OscillatorNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = Nodes_pos[i].node;
        }
        break;
      case "AudioBufferSourceNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.AudioBufferSourceNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.AudioBufferSourceNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = Nodes_pos[i].node;
        }
        break;
      case "StereoPannerNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.StereoPannerNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.StereoPannerNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = Nodes_pos[i].node;
        }
        break;
    }
  }

  for (let i = 0; i < NodesCtx_pos.length; i++) {
    nodeName = NodesCtx_pos[i].node.split(" ");
    nodeXY   = NodesCtx_pos[i].posXY.split(",");
    nodeX    = parseInt(nodeXY[0]);
    nodeY    = parseInt(nodeXY[1]);

    switch(nodeName[0]) {
      case "GainNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.GainNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.GainNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = NodesCtx_pos[i].node;
        }
        break;
      case "ConvolverNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.ConvolverNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.ConvolverNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = NodesCtx_pos[i].node;
        }
        break;
      case "DynamicsCompressorNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.DynamicsCompressorNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.DynamicsCompressorNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = NodesCtx_pos[i].node;
        }
        break;
      case "AnalyserNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.AnalyserNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.AnalyserNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = NodesCtx_pos[i].node;
        }
        break;
      case "AudioDestinationNode":
        if (nodeX < mouseX && mouseX < nodeX + parseInt(Nodes_size.AudioDestinationNode.x) &&
          nodeY < mouseY && mouseY < nodeY + parseInt(Nodes_size.AudioDestinationNode.y)) {
          audiograph.style.cursor = "pointer";
          audiograph_node = NodesCtx_pos[i].node;
        }
        break;
    }
  }
}
/**
 * [soundeditorGM_info description]
 * @param  {[type]} id [description]
 */
function soundeditorGM_info(id){
  let descr_ul = document.getElementById("descr_ul");
  let img_ahdsr   = document.getElementById("img_ahdsr");

  img_ahdsr.style.display = "none";
  descr_ul.style.display = "block";
  descr_ul.setAttribute("style", "margin: 0px;padding:0;font-size:14px;color:black;font-family: 'Arial, Helvetica, sans-serif'");

  switch(id){
    case "soundeditorGM_th1":
      let li1_1 = document.createElement("li");
      let li1_2 = document.createElement("li");

      li1_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");
      li1_2.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");

      li1_1.innerHTML = "<b>g0</b>: output destination - final output";
      li1_2.innerHTML = "<b>gn</b>: output destination - to specified osc";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li1_1);
      descr_ul.appendChild(li1_2);
      break;
    case "soundeditorGM_th2":
      let li2_1 = document.createElement("li");
      let li2_2 = document.createElement("li");
      let li2_3 = document.createElement("li");
      let li2_4 = document.createElement("li");

      li2_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");
      li2_2.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");
      li2_3.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");
      li2_4.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;z-index: 1");

      li2_1.innerHTML = "w: waveform - (basic waveforms): sine/sawtooth/square/triangle";
      li2_2.innerHTML = "w: waveform - (summing 1-4 harmonics): w9999";
      li2_3.innerHTML = "w: waveform - (white noise): n0";
      li2_4.innerHTML = "w: waveform - (metalic noise): n1";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li2_1);
      descr_ul.appendChild(li2_2);
      descr_ul.appendChild(li2_3);
      descr_ul.appendChild(li2_4);
      break;
    case "soundeditorGM_th3":
      let li3_1 = document.createElement("li");

      li3_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;");

      li3_1.innerHTML = "volume";

      descr_ul.innerHTML= "";
      descr_ul.appendChild(li3_1);
      break;
    case "soundeditorGM_th4":
      let li4_1 = document.createElement("li");

      li4_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;");

      li4_1.innerHTML = "tune factor according to note#";

      descr_ul.innerHTML= "";
      descr_ul.appendChild(li4_1);
      break;
    case "soundeditorGM_th5":
      let li5_1 = document.createElement("li");

      li5_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;");

      li5_1.innerHTML = "fixed frequency in Hz";

      descr_ul.innerHTML= "";
      descr_ul.appendChild(li5_1);
      break;
    case "soundeditorGM_th6":
      let li6 = document.createElement("li");

      li6.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:pointer;");
      li6.classList.add("AHDSR");

      li6.innerHTML = "<b>Attack</b>: This is the first stage, during which the control voltage rises from its initial value (usually zero) to its peak value. The attack time determines how quickly this rise occurs, with shorter attack times producing a faster, more immediate onset of the sound, and longer attack times creating a slower, more gradual increase in amplitude or other parameter.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li6);
      break;
    case "soundeditorGM_th7":
      let li7 = document.createElement("li");

      li7.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:pointer;");
      li7.classList.add("AHDSR");

      li7.innerHTML = "<b>Hold</b>: This is the second stage, during which the control voltage remains at its peak value for a specified period. The hold time determines the duration of this constant level, allowing for a sustained peak before the envelope proceeds to the decay stage.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li7);
      break;
    case "soundeditorGM_th8":
      let li8 = document.createElement("li");

      li8.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:pointer;");
      li8.classList.add("AHDSR");

      li8.innerHTML = "<b>Decay</b>: This is the third stage, during which the control voltage falls from its peak value to the sustain level. The decay time determines how quickly this decrease occurs, with shorter decay times producing a faster transition, and longer decay times resulting in a slower, more gradual change.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li8);
      break;
    case "soundeditorGM_th9":
      let li9 = document.createElement("li");

      li9.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:pointer;");
      li9.classList.add("AHDSR");

      li9.innerHTML = "<b>Sustain</b>: This is the fourth stage, during which the control voltage remains at a constant level while a note is held or a gate signal is active. The sustain level determines the amplitude or intensity of the sound during this stage, with higher sustain levels resulting in louder or more pronounced sounds, and lower sustain levels producing quieter or more subdued sounds.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li9);
      break;
    case "soundeditorGM_th10":
      let li10 = document.createElement("li");

      li10.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:pointer;");
      li10.classList.add("AHDSR");

      li10.innerHTML = "<b>Release</b>: This is the final stage, during which the control voltage falls from the sustain level back to its initial value after a note is released or the gate signal is deactivated. The release time determines how quickly this decrease occurs, with shorter release times producing a faster, more abrupt fade-out of the sound, and longer release times resulting in a slower, more gradual decay.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li10);
      break;
    case "soundeditorGM_th11":
      let li11_1 = document.createElement("li");
      let li11_2 = document.createElement("li");

      li11_1.setAttribute("style", "margin-left: 20px;line-height:1.2;cursor:default;");
      li11_2.setAttribute("style", "margin-left: 20px;line-height:1.2;cursor:default;");

      li11_1.innerHTML= "<b>setBend(ch, val, t)</b>: Set pitch bend state. Notes in this channel are all affected to this pitch modification. val range is 0 to 16384 and the center with no bend is 8192. sensitivity is depends on setBendRange() setting. Default state is 8192.";
      descr_ul.appendChild(li11_1);

      li11_2.innerHTML= "<b>setBendRange(ch, val)</b>: Set bend sensitivity for that channel. val unit is 100/127 cent. That means +-1 octave if 0x600, +-1 semitone if 0x80. Default value is 0x100 that means +-200 cent (2 semitone) range.";

      descr_ul.innerHTML = "";
      descr_ul.appendChild(li11_1);
      descr_ul.appendChild(li11_2);

      break;
    case "soundeditorGM_th12":
      let li12_1 = document.createElement("li");

      li12_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;");

      li12_1.innerHTML = "pitch bend speed factor";

      descr_ul.innerHTML= "";
      descr_ul.appendChild(li12_1);
      break;
    case "soundeditorGM_th13":
      let li13_1 = document.createElement("li");

      li13_1.setAttribute("style", "margin-left: 20px;line-height:1.4;cursor:default;");

      li13_1.innerHTML = "volume key tracking factor";

      descr_ul.innerHTML= "";
      descr_ul.appendChild(li13_1);
      break;
  }
}
function view_ahdsr_img() {
  let descr_ul  = document.getElementById("descr_ul");
  let descr_li  = document.getElementById("descr_ul").querySelector(".AHDSR");
  let img_ahdsr = document.getElementById("img_ahdsr");

  if (descr_li){
    if("none" == img_ahdsr.style.display) {
      descr_ul.style.display = "none";
      img_ahdsr.style.display = "block";
    }else{
      descr_ul.style.display = "block";
      img_ahdsr.style.display = "none";
    }
  }else{
    descr_ul.style.display = "block";
    img_ahdsr.style.display = "none";
  }
}
/**
 * [img_resize description]
 * @param  {[type]} id [description]
 * @return {[type]}    [description]
 */
function img_resize(id) {
 let img = document.getElementById(id);

 switch(id){
    case "webaudiothreshold":
      if ("70px" == img.style.width) {
        img.setAttribute("style", "position:absolute;z-index: 1;left:5px;top:-5px;width:255px;height:305px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }else{
        img.setAttribute("style", "position:absolute;z-index: auto;left:180px;top:20px;width:70px;height:50px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }
      break;
    case "webaudioknee":
      if ("70px" == img.style.width) {
        img.setAttribute("style", "position:absolute;z-index: 1;left:5px;top:-5px;width:255px;height:305px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }else{
        img.setAttribute("style", "position:absolute;z-index: auto;left:180px;top:77px;width:70px;height:50px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }
      break;
    case "webaudioratio":
      if ("70px" == img.style.width) {
        img.setAttribute("style", "position:absolute;z-index: 1;left:5px;top:-5px;width:255px;height:305px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }else{
        img.setAttribute("style", "position:absolute;z-index: auto;left:180px;top:134px;width:70px;height:50px;margin:0 5px;border: 1px solid black;cursor:pointer;");
      }
      break;
  }
}
function patchLoad(){
  let patch = document.getElementById("patch");
  let str = localStorage.getItem("Prog_"+curProg+"_patch");
  let pg = {};

  pg.name = document.getElementById("prog_name").innerHTML;
  let arr = str.split(";");
  arr.forEach(function(item, index){
    arr[index] = JSON.parse(item);
  });
  pg.p = arr;

  ViewParam(pg);
  tblTimbreGM();

  patch.value = str;
  //Working with patch...

  inform_panel.style.color = "#A0A378";
  inform_panel.innerHTML = "Patch loaded from local storage";
}
function patchSave(){
  let patch = document.getElementById("patch");

  localStorage.setItem("Prog_"+curProg+"_patch",patch.value);

  inform_panel.style.color = "#A0A378";
  inform_panel.innerHTML = "Patch saved to local storage";
}
function patchDelete(){
  let patch = document.getElementById("patch");

  localStorage.removeItem("Prog_"+curProg+"_patch");

  inform_panel.style.color = "#A0A378";
  inform_panel.innerHTML = "Patch delete from local storage";
}
/**
 * Distributes a click event to the associated standardMIDI element.
 * @param  string id ID stdGM,stdGS,stdXG
 */
function selStandMidi(id){
  let itemsGS = localStorage.getItem("soundFontsGS");
  let itemsXG = localStorage.getItem("soundFontsXG");

  curBank = 0;
  curPreset = 0;
  curNote = 60;
  curProg = 0;
  curOct  = 0;
  curCh = 0;

  prog.value = 0;
  prog_num.value = 0;

  let keyNum = synth.arrNotes[curNote-21];
  document.getElementById("shotBtn").innerHTML= (keyNum) ? keyNum :"--";

  if(true == synth.playing) synth.stopMIDI();

  resetAllBtns();

  switch(id){
    case "GM":
      document.getElementById("soundeditorGM").style.display = "table";
      document.getElementById("sf2viewer").style.display = "none";

      document.getElementById("GM").setAttribute("value",1);
      document.getElementById("GM").value = 1;
      document.getElementById("GM").checked = true;

      document.getElementById("GS").setAttribute("value",0);
      document.getElementById("GS").value = 0;
      document.getElementById("XG").setAttribute("value",0);
      document.getElementById("XG").value = 0;

      standMidi = "GM";
      InitApp();
      Sequencer();

      inform_panel.style.color = "#A0A378";
      inform_panel.innerHTML = "GM tones map installed.";
      break;
    case "GS":
      document.getElementById("soundeditorGM").style.display = "none";
      document.getElementById("sf2viewer").style.display = "block";
      document.getElementById("soundViewerGSXG").style.display = "table";

      document.getElementById("GS").setAttribute("value",1);
      document.getElementById("GS").value = 1;
      document.getElementById("GS").checked = true;

      document.getElementById("GM").setAttribute("value",0);
      document.getElementById("GM").value = 0;
      document.getElementById("XG").setAttribute("value",0);
      document.getElementById("XG").value = 0;

      standMidi = "GS";

      let valGS = document.getElementById("GS").getAttribute("soundfonts");
      if(null !== valGS){
        let tblBody = document.querySelector("#soundViewerGSXG tbody");
        tblBody.innerHTML = "";
        //loader on
        let loader3 = document.createElement("div");
        loader3.className = "loader3";
        document.getElementById("sf2viewer").appendChild(loader3);

        valGS = valGS.split("|");
        let fileNameSF = valGS[0];

        if("local" == valGS[3]){
          // Installing downloaded SoundFontsSF into the synthesizer
          getLocalSoundFonts(fileNameSF,"GS")
          .then(contentSF => installSoundFonts(fileNameSF, contentSF))
          .then(activeZones => tblTimbreSF(activeZones))
          .then(result => audioNodesDiagram())
          .then(() => Sequencer())
          .then(() => infoFileSF())
          .then(() => getInfoPrmSF('banks', curBank, '', 'banks'))
          .then(() => synth.getProgNameSF(curBank, curPreset))
          .then((presetName) => getInfoPrmSF('presets', presetName, curPreset, 'presets'));
        }
        if("remote" == valGS[3]){
          // Installing downloaded SoundFontsSF into the synthesizer
          getRemoteSoundFonts(fileNameSF,"GS")
          .then(contentSF => installSoundFonts(fileNameSF, contentSF))
          .then(activeZones => tblTimbreSF(activeZones))
          .then(result => audioNodesDiagram())
          .then(() => Sequencer())
          .then(() => infoFileSF())
          .then(() => getInfoPrmSF('banks', curBank, '', 'banks'))
          .then(() => synth.getProgNameSF(curBank, curPreset))
          .then((presetName) => getInfoPrmSF('presets', presetName, curPreset, 'presets'));
        }
      }
      break;
    case "XG":
      document.getElementById("soundeditorGM").style.display = "none";
      document.getElementById("sf2viewer").style.display = "block";
      document.getElementById("soundViewerGSXG").style.display = "table";

      document.getElementById("XG").setAttribute("value",1);
      document.getElementById("XG").value = 1;
      document.getElementById("XG").checked = true;

      document.getElementById("GM").setAttribute("value",0);
      document.getElementById("GM").value = 0;
      document.getElementById("GS").setAttribute("value",0);
      document.getElementById("GS").value = 0;

      standMidi = "XG";

      document.getElementById("soundeditorGM").style.display = "none";
      document.getElementById("soundViewerGSXG").style.display = "table";

      let valXG = document.getElementById("XG").getAttribute("soundfonts");
      if(null !== valXG){
        let tblBody = document.querySelector("#soundViewerGSXG tbody");
        tblBody.innerHTML = "";
        //loader on
        let loader3 = document.createElement("div");
        loader3.className = "loader3";
        document.getElementById("sf2viewer").appendChild(loader3);

        valXG = valXG.split("|");
        let fileNameSF = valXG[0];
        if("local" == valXG[3]){
          // Installing downloaded SoundFontsSF into the synthesizer
          getLocalSoundFonts(fileNameSF,"XG")
          .then(contentSF => installSoundFonts(fileNameSF, contentSF))
          .then(activeZones => tblTimbreSF(activeZones))
          .then(result => audioNodesDiagram())
          .then(() => Sequencer())
          .then(() => infoFileSF())
          .then(() => getInfoPrmSF('banks', curBank, '', 'banks'))
          .then(() => synth.getProgNameSF(curBank, curPreset))
          .then((presetName) => getInfoPrmSF('presets', presetName, curPreset, 'presets'));
        }
        if("remote" == valXG[3]){
          // Installing downloaded SoundFontsSF into the synthesizer
          getRemoteSoundFonts(fileNameSF,"XG")
          .then(contentSF => installSoundFonts(fileNameSF, contentSF))
          .then(activeZones => tblTimbreSF(activeZones))
          .then(result => audioNodesDiagram())
          .then(() => Sequencer())
          .then(() => infoFileSF())
          .then(() => getInfoPrmSF('banks', curBank, '', 'banks'))
          .then(() => synth.getProgNameSF(curBank, curPreset))
          .then((presetName) => getInfoPrmSF('presets', presetName, curPreset, 'presets'));
        }
      }
  }
  synth.setStandMidi(standMidi);
}
