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

"use strict";

var ctxGraph;

var GridNodes = [
  ["x0/y0", "x0/y1", "x0/y2", "x0/y3"],
  ["x1/y0", "x1/y1", "x1/y2", "x1/y3"],
  ["x2/y0", "x2/y1", "x2/y2", "x2/y3"],
  ["x3/y0", "x3/y1", "x3/y2", "x3/y3"],
  ["x4/y0", "x4/y1", "x4/y2", "x4/y3"],
  ["x5/y0", "x5/y1", "x5/y2", "x5/y3"]
];

var Nodes_pins = {"GainNode": {"in": "0,25", "gain": "0,40", "out": "70,25"},
									"OscillatorNode": {"f": "0,25", "d": "0,40", "out": "90,25"},
									"AudioBufferSourceNode": {"b": "0,25", "d": "0,40", "out": "90,25"},
									"StereoPannerNode": {"in": "0,25", "pan": "0,42", "out": "110,25"},
									"ConvolverNode": {"in": "0,25", "out": "90,25"},
									"AnalyserNode": {"in": "0,25", "out": "90,25"},
									"AudioDestinationNode": {"in": "0,12"},
									"DynamicsCompressorNode": {"in": "0,20", "th": "0,32", "kn": "0,42", "ra": "0,52", "at": "0,62", "re": "0,72", "out": "150,40"}};

var Nodes_size = {"GainNode": {"x": "70", "y": "50"},
									"OscillatorNode": {"x": "90", "y": "50"},
									"AudioBufferSourceNode": {"x": "90", "y": "50"},
									"StereoPannerNode": {"x": "110", "y": "50"},
									"ConvolverNode": {"x": "90", "y": "50"},
									"AnalyserNode": {"x": "90", "y": "50"},
									"AudioDestinationNode": {"x": "190", "y": "25"},
									"DynamicsCompressorNode": {"x": "150", "y": "80"}};


var Nodes_pos    = [];
var NodesCtx_pos = [];

function drawInfoBox(){
	let AudioNodesPrm    = synth.getAudioNodesPrm();
	let AudioNodesCtxPrm = synth.getAudioNodesCtxPrm();
	let AllaudioNodesPrm = AudioNodesPrm.concat(AudioNodesCtxPrm);

	ctxGraph.fillStyle = "#C3C3C3";
	ctxGraph.beginPath();
	ctxGraph.fillRect(720, 2, 258, 304);
	ctxGraph.fill();

	ctxGraph.font = "16px sans-serif";
	//imgs
  document.getElementById("canvas_imgs").style.display = "none";

	if ("" == audiograph_node_click) {
		if("GM" == standMidi){
			ctxGraph.font = "16px sans-serif";
			//No Name audioNode.
			ctxGraph.fillStyle = "white";
			ctxGraph.textAlign = "center";
			ctxGraph.fillText("AudioParam of selected Node", 850, 155);
		}else{
			drawMetaDataSF2();
		}
	}else{
		ctxGraph.font = "bold 16px sans-serif";
		//Name audioNode.
		ctxGraph.fillStyle = "#37474F";
		ctxGraph.textAlign = "left";

		for(let i = 0; i < AllaudioNodesPrm.length; i++){
			if (audiograph_node_click == AllaudioNodesPrm[i].nodeName) {
				ctxGraph.fillText(AllaudioNodesPrm[i].nodeName, 725, 15);

				let nodeName = AllaudioNodesPrm[i].nodeName.split(" ");

				switch(nodeName[0]) {
					case "OscillatorNode":
						ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("channelCount", 725, 35);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.channelCount, 860, 35);

						ctxGraph.fillText("channelCountMode", 725, 50);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.channelCountMode, 860, 50);

						ctxGraph.fillText("channelInterpretation", 725, 65);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.channelInterpretation, 860, 65);

						ctxGraph.fillText("numberOfInputs", 725, 80);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.numberOfInputs, 860, 80);

						ctxGraph.fillText("numberOfOutputs", 725, 95);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.numberOfOutputs, 860, 95);

						ctxGraph.fillText("type", 725, 110);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.type, 860, 110);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("detune: AudioParam", 725, 135);

						ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("automationRate", 725, 150);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.detune.automationRate, 860, 150);

						ctxGraph.fillText("defaultValue", 725, 165);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.detune.defaultValue, 860, 165);

						ctxGraph.fillText("maxValue", 725, 180);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.detune.maxValue, 860, 180);

						ctxGraph.fillText("minValue", 725, 195);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.detune.minValue, 860, 195);

						ctxGraph.fillText("value", 725, 210);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.detune.value.toFixed(3), 860, 210);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("frequency: AudioParam", 725, 230);

						ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("automationRate", 725, 245);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.frequency.automationRate, 860, 245);

						ctxGraph.fillText("defaultValue", 725, 260);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.frequency.defaultValue, 860, 260);

						ctxGraph.fillText("maxValue", 725, 275);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.frequency.maxValue, 860, 275);

						ctxGraph.fillText("minValue", 725, 290);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.frequency.minValue, 860, 290);

						ctxGraph.fillText("value", 725, 305);
						ctxGraph.fillText(AllaudioNodesPrm[i].osc.frequency.value.toFixed(3), 860, 305);

				    break;
				  case "AudioBufferSourceNode":
				  	ctxGraph.font = "bold 14px sans-serif";

				  	ctxGraph.fillText("buffer: AudioBuffer", 725, 40);

				  	ctxGraph.font = "normal 14px sans-serif";

				  	ctxGraph.fillText("duration", 725, 60);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.buffer.duration, 860, 60);

						ctxGraph.fillText("length", 725, 75);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.buffer.length, 860, 75);

						ctxGraph.fillText("numberOfChannels", 725, 90);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.buffer.numberOfChannels, 860, 90);

						ctxGraph.fillText("sampleRate", 725, 105);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.buffer.sampleRate, 860, 105);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("detune: AudioParam", 725, 130);

						ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("automationRate", 725, 150);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.detune.automationRate, 860, 150);

						ctxGraph.fillText("defaultValue", 725, 165);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.detune.defaultValue, 860, 165);

						ctxGraph.fillText("maxValue", 725, 180);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.detune.maxValue, 800, 180);

						ctxGraph.fillText("minValue", 725, 195);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.detune.minValue, 800, 195);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("playbackRate: AudioParam", 725, 220);

						ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("automationRate", 725, 240);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.playbackRate.automationRate, 860, 240);

						ctxGraph.fillText("defaultValue", 725, 255);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.playbackRate.defaultValue, 860, 255);

						ctxGraph.fillText("maxValue", 725, 270);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.playbackRate.maxValue, 800, 270);

						ctxGraph.fillText("minValue", 725, 285);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.playbackRate.minValue, 800, 285);

						ctxGraph.fillText("value", 725, 300);
						ctxGraph.fillText(AllaudioNodesPrm[i].buf.playbackRate.value.toFixed(3), 800, 300);
				  	break;
				  case "StereoPannerNode":
				  	ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("channelCount", 725, 40);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.channelCount, 860, 40);

						ctxGraph.fillText("channelCountMode", 725, 55);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.channelCountMode, 860, 55);

						ctxGraph.fillText("channelInterpretation", 725, 70);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.channelInterpretation, 860, 70);

						ctxGraph.fillText("numberOfInputs", 725, 85);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.numberOfInputs, 860, 85);

						ctxGraph.fillText("numberOfOutputs", 725, 100);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.numberOfOutputs, 860, 100);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("pan: AudioParam", 725, 125);

						ctxGraph.font = "normal 14px sans-serif";

				  	ctxGraph.fillText("automationRate", 725, 145);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.pan.automationRate, 860, 145);

						ctxGraph.fillText("defaultValue", 725, 160);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.pan.defaultValue, 860, 160);

						ctxGraph.fillText("pan: maxValue", 725, 175);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.pan.maxValue, 860, 175);

						ctxGraph.fillText("pan: minValue", 725, 190);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.pan.minValue, 860, 190);

						ctxGraph.fillText("pan: value", 725, 205);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.pan.value, 860, 205);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("context: AudioContext", 725, 230);

						ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("baseLatency", 725, 250);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.context.baseLatency, 860, 250);

						ctxGraph.fillText("outputLatency", 725, 265);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.context.outputLatency.toFixed(3), 860, 265);

						ctxGraph.fillText("sampleRate", 725, 280);
						ctxGraph.fillText(AllaudioNodesPrm[i].pan.context.sampleRate, 860, 280);
				    break;
				  case "GainNode":
				  	ctxGraph.font = "normal 13px sans-serif";
				  	ctxGraph.fillText("channelCount", 725, 40);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.channelCount, 860, 40);

						ctxGraph.fillText("channelCountMode", 725, 55);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.channelCountMode, 860, 55);

						ctxGraph.fillText("channelInterpretation", 725, 70);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.channelInterpretation, 860, 70);

						ctxGraph.fillText("numberOfInputs", 725, 85);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.numberOfInputs, 860, 85);

						ctxGraph.fillText("numberOfOutputs", 725, 100);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.numberOfOutputs, 860, 100);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("gain: AudioParam", 725, 125);

						ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("automationRate", 725, 145);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.gain.automationRate, 860, 145);

						ctxGraph.fillText("defaultValue", 725, 160);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.gain.defaultValue, 860, 160);

						ctxGraph.fillText("maxValue", 725, 175);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.gain.maxValue, 800, 175);

						ctxGraph.fillText("minValue", 725, 190);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.gain.minValue, 800, 190);

						ctxGraph.fillText("value", 725, 205);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.gain.value, 800, 205);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("context: AudioContext", 725, 230);

						ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("baseLatency", 725, 250);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.context.baseLatency, 860, 250);

						ctxGraph.fillText("outputLatency", 725, 265);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.context.outputLatency.toFixed(3), 860, 265);

						ctxGraph.fillText("sampleRate", 725, 280);
						ctxGraph.fillText(AllaudioNodesPrm[i].gain.context.sampleRate, 860, 280);

				    break;
				  case "ConvolverNode":
				  	ctxGraph.font = "normal 14px sans-serif";

				  	ctxGraph.fillText("channelCount", 725, 40);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.channelCount, 860, 40);

						ctxGraph.fillText("channelCountMode", 725, 55);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.channelCountMode, 860, 55);

						ctxGraph.fillText("channelInterpretation", 725, 70);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.channelInterpretation, 860, 70);

						ctxGraph.fillText("numberOfInputs", 725, 85);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.numberOfInputs, 860, 85);

						ctxGraph.fillText("numberOfOutputs", 725, 100);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.numberOfOutputs, 860, 100);

						ctxGraph.fillText("normalize", 725, 115);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.normalize, 860, 115);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("buffer: AudioBuffer", 725, 145);

						ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("duration", 725, 165);
						ctxGraph.fillText(conv_duration.value, 860, 165);

						ctxGraph.fillText("decay", 725, 180);
						ctxGraph.fillText(conv_decay.value, 860, 180);

						ctxGraph.fillText("length", 725, 195);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.buffer.length, 860, 195);

						ctxGraph.fillText("numberOfChannels", 725, 210);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.buffer.numberOfChannels, 860, 210);

						ctxGraph.fillText("sampleRate", 725, 225);
						ctxGraph.fillText(AllaudioNodesPrm[i].conv.buffer.sampleRate, 860, 225);

				    break;
				  case "DynamicsCompressorNode":
						document.getElementById("canvas_imgs").setAttribute("style", "position: relative;left: 720px;top: -305px;z-index:1;display:block;");
				  	ctxGraph.font = "bold 14px sans-serif";
				  	ctxGraph.fillText("threshold: AudioParam", 725, 35);

				  	ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("maxValue", 725, 49);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.threshold.maxValue, 860, 49);

						ctxGraph.fillText("minValue", 725, 63);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.threshold.minValue, 860, 63);

						ctxGraph.fillText("value", 725, 77);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.threshold.value, 860, 77);

						ctxGraph.font = "bold 14px sans-serif";
				  	ctxGraph.fillText("knee: AudioParam", 725, 91);

				  	ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("maxValue", 725, 105);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.knee.maxValue, 860, 105);

						ctxGraph.fillText("minValue", 725, 119);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.knee.minValue, 860, 119);

						ctxGraph.fillText("value", 725, 134);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.knee.value, 860, 134);

						ctxGraph.font = "bold 14px sans-serif";
				  	ctxGraph.fillText("ratio: AudioParam", 725, 148);

				  	ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("maxValue", 725, 162);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.ratio.maxValue, 860, 162);

						ctxGraph.fillText("minValue", 725, 176);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.ratio.minValue, 860, 176);

						ctxGraph.fillText("value", 725, 190);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.ratio.value, 860, 190);

						ctxGraph.font = "bold 14px sans-serif";
				  	ctxGraph.fillText("attack: AudioParam", 725, 204);

				  	ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("maxValue", 725, 218);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.attack.maxValue, 860, 218);

						ctxGraph.fillText("minValue", 725, 232);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.attack.minValue, 860, 232);

						ctxGraph.fillText("value", 725, 246);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.attack.value.toFixed(3), 860, 246);

						ctxGraph.font = "bold 14px sans-serif";
				  	ctxGraph.fillText("release: AudioParam", 725, 260);

				  	ctxGraph.font = "normal 14px sans-serif";

						ctxGraph.fillText("maxValue", 725, 274);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.release.maxValue, 860, 274);

						ctxGraph.fillText("minValue", 725, 288);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.release.minValue, 860, 288);

						ctxGraph.fillText("value", 725, 302);
						ctxGraph.fillText(AllaudioNodesPrm[i].comp.release.value.toFixed(3), 860, 302);

				    break;
				  case "AnalyserNode":
				  	ctxGraph.font = "normal 14px sans-serif";

				  	ctxGraph.fillText("channelCount", 725, 40);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.channelCount, 890, 40);

						ctxGraph.fillText("channelCountMode", 725, 55);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.channelCountMode, 890, 55);

						ctxGraph.fillText("channelInterpretation", 725, 70);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.channelInterpretation, 890, 70);

						ctxGraph.fillText("numberOfInputs", 725, 85);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.numberOfInputs, 890, 85);

						ctxGraph.fillText("numberOfOutputs", 725, 100);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.numberOfOutputs, 890, 100);

						ctxGraph.fillText("fftSize", 725, 115);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.fftSize, 890, 115);

						ctxGraph.fillText("frequencyBinCount", 725, 130);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.frequencyBinCount, 890, 130);

						ctxGraph.fillText("maxDecibels", 725, 145);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.maxDecibels, 890, 145);

						ctxGraph.fillText("minDecibels", 725, 160);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.minDecibels, 890, 160);

						ctxGraph.fillText("numberOfInputs", 725, 175);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.numberOfInputs, 890, 175);

						ctxGraph.fillText("numberOfOutputs", 725, 190);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.numberOfOutputs, 890, 190);

						ctxGraph.fillText("smoothingTimeConstant", 725, 205);
						ctxGraph.fillText(AllaudioNodesPrm[i].analys.smoothingTimeConstant, 890, 205);
				    break;
				  case "AudioDestinationNode":
				  	ctxGraph.font = "normal 14px sans-serif";

				  	ctxGraph.fillText("channelCount", 725, 40);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.channelCount, 890, 40);

						ctxGraph.fillText("channelCountMode", 725, 55);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.channelCountMode, 890, 55);

						ctxGraph.fillText("channelInterpretation", 725, 70);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.channelInterpretation, 890, 70);

						ctxGraph.fillText("maxChannelCount", 725, 85);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.maxChannelCount, 890, 85);

						ctxGraph.fillText("numberOfInputs", 725, 100);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.numberOfInputs, 890, 100);

						ctxGraph.fillText("numberOfOutputs", 725, 115);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.numberOfOutputs, 890, 115);

						ctxGraph.font = "bold 14px sans-serif";
						ctxGraph.fillText("context: AudioContext", 725, 135);

						ctxGraph.font = "normal 13px sans-serif";

						ctxGraph.fillText("baseLatency", 725, 150);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.context.baseLatency, 890, 150);

						ctxGraph.fillText("outputLatency", 725, 165);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.context.outputLatency.toFixed(3), 890, 165);

						ctxGraph.fillText("sampleRate", 725, 180);
						ctxGraph.fillText(AllaudioNodesPrm[i].dest.context.sampleRate, 890, 180);

				    break;
				}
			}
		}
	}
	// console.log("Nodes_pos", Nodes_pos);
}
/**
 * Create Grid of Nodes on Diagram.
 */
function createGridNodes(){
	let head_audiograph_prog_num;
  let head_audiograph_prog_name;
  let head_audiograph_note_name;
  let progName;

	return new Promise((resolve, reject) => {
		//Clear canvas
	  ctxGraph = audiograph.getContext("2d");
	  ctxGraph.clearRect(0, 0, audiograph.width, audiograph.height);

	  if(9 == curCh){
	  	head_audiograph_prog_num  = "Graph of program[" + curNote + "]";
		  head_audiograph_prog_name = synth.getProgNameGM(1,curNote-35);
		  head_audiograph_note_name = "Note "+synth.arrNotes[curNote-21] + " [" + curNote + "]";
	  }else{
	  	if("GM" == standMidi){
	  		progName = synth.getProgNameGM(0, curProg);
	  	}else{
	  		progName = synth.getProgNameSF(curBank, curProg);
	  	}
	  	head_audiograph_prog_num  = "Graph of program[" + curProg + "]";
		  head_audiograph_prog_name = progName;
		  head_audiograph_note_name = "Note "+synth.arrNotes[curNote-21] + " [" + curNote + "]";
	  }
	  ctxGraph.font = "bold 16px sans-serif";
	  ctxGraph.fillStyle = "#7F7F7F";
	  ctxGraph.textAlign = "left";
	  ctxGraph.fillText(head_audiograph_prog_num, 520, 30);
	  ctxGraph.fillText(head_audiograph_prog_name, 520, 50);
	  ctxGraph.fillText(head_audiograph_note_name, 520, 70);

		// Box width
		let bw = audiograph.width;
		// Box height
		let bh = 240;
		// Padding
		let p = 1;

		// Draw the grid

	  // for (let y = 0; y <= bw; y += 120) {
	  //   ctxGraph.moveTo(0.5 + y + p, p);
	  //   ctxGraph.lineTo(0.5 + y + p, bh - 20*p);
	  // }
	  // for (let x = 0; x <= bh; x += 55) {
	  //   ctxGraph.moveTo(p, 0.5 + x + p);
	  //   ctxGraph.lineTo(bw + p, 0.5 + x + p);
	  // }
	  // ctxGraph.strokeStyle = "black";
	  // ctxGraph.stroke();

	  //Create nodes of grid.
	  let nodeX = p;
	  let nodeY = p;
	  for (let x = 0; x <= 5; x++) {
	  	for (let y = 0; y <= 3; y++) {
	  		GridNodes[x][y] = nodeX + "," + nodeY;
	  		nodeY = nodeY + 55;
	  	}
	  	nodeY = p;
	  	nodeX = nodeX + 120;
	  }
	  return resolve(true);
	});
}
/**
 * Create Diagram of AudioNodes.
 */
function audioNodesDiagram(){
	Nodes_pos    = [];
  NodesCtx_pos = [];

  //Clear canvas
  ctxGraph = audiograph.getContext("2d");
  ctxGraph.clearRect(0, 0, audiograph.width, audiograph.height);

	createGridNodes()
	.then(gridNodes => drawAudioNodes())
	.then(nodePos => audioNodeLinks())
	.then(gridNodesCtx => drawAudioNodesCtx())
	.then(nodePosCtx => audioNodeCtxLinks())
	.then(drawInfoBox());
}
/**
 * Drawing connections between audio nodes.
 */
function audioNodeCtxLinks(){
	var audioNodesCtx = synth.getAudioNodesCtx();
	var audiograph = document.getElementById("audiograph");
	var ctx = audiograph.getContext("2d");

	var node1_X1;
	var node1_Y1;
	var node2_X2;
	var node2_Y2;

	//Удаляю эту связи и рисую ее вручную внизу этой функции
	//т.к. связь проходит поверх двух узлов.
	if (7 == audioNodesCtx.length) {
		audioNodesCtx.splice(3, 1);
	}

	audioNodesCtx.forEach((nodes)=> {
		// Node1---------------------------------------------
		let node1 = NodesCtx_pos.filter((el1) => {
			let search1 = JSON.stringify(el1).indexOf(nodes.node1);
			if (-1 != search1) {
				return search1;
			}
		});
		let node1_posXY = node1[0].posXY.split(",");
		let pos1_X = node1_posXY[0];
		let pos1_Y = node1_posXY[1];

		let el1 = nodes.node1.split(" ");
		let el1_x_y;

		switch(el1[0]) {
		  case "GainNode":
		  	el1_x_y = Nodes_pins.GainNode.out.split(",");
		    break;
		  case "ConvolverNode":
		  	el1_x_y = Nodes_pins.ConvolverNode.out.split(",");
		    break;
		  case "DynamicsCompressorNode":
		  	el1_x_y = Nodes_pins.DynamicsCompressorNode.out.split(",");
		    break;
		  case "AnalyserNode":
		  	el1_x_y = Nodes_pins.AnalyserNode.out.split(",");
		    break;
		  case "AudioDestinationNode":
		  	el1_x_y = Nodes_pins.AudioDestinationNode.out.split(",");
		    break;
		}
		node1_X1 = parseInt(pos1_X) + parseInt(el1_x_y[0]);
		node1_Y1 = parseInt(pos1_Y) + parseInt(el1_x_y[1]);
		// Node2---------------------------------------------
		let node2 = NodesCtx_pos.filter((el2) => {
			let search2 = JSON.stringify(el2).indexOf(nodes.node2);
			if (-1 != search2) {
				return search2;
			}
		});
		let node2_posXY = node2[0].posXY.split(",");
		let pos2_X = node2_posXY[0];
		let pos2_Y = node2_posXY[1];

		let el2 = nodes.node2.split(" ");
		let el2_x_y;

		switch(el2[0]) {
		  case "GainNode":
		  	el2_x_y = Nodes_pins.GainNode.in.split(",");
		    break;
		  case "ConvolverNode":
		  	el2_x_y = Nodes_pins.ConvolverNode.in.split(",");
		    break;
		  case "DynamicsCompressorNode":
		  	el2_x_y = Nodes_pins.DynamicsCompressorNode.in.split(",");
		    break;
		  case "AnalyserNode":
		  	el2_x_y = Nodes_pins.AnalyserNode.in.split(",");
		    break;
		  case "AudioDestinationNode":
		  	el2_x_y = Nodes_pins.AudioDestinationNode.in.split(",");
		    break;
		}
		node2_X2 = parseInt(pos2_X) + parseInt(el2_x_y[0]);
		node2_Y2 = parseInt(pos2_Y) + parseInt(el2_x_y[1]);

		//Draw lines...
		ctxGraph.beginPath();
		ctxGraph.moveTo(node1_X1, node1_Y1);
		ctxGraph.lineTo(node2_X2, node2_Y2);
		ctxGraph.stroke();
	});
	// Another connection.
	ctxGraph.beginPath();
	ctxGraph.moveTo(80, 250);
	ctxGraph.lineTo(110, 290);
	ctxGraph.lineTo(300, 290);
	ctxGraph.lineTo(330, 245);
	ctxGraph.stroke();

	return true;
}
/**
 * Drawing nodesName of audio nodes.
 */
function audioNodesProgName(){

	return new Promise((resolve, reject) => {
		var audioNodesProg = synth.getAudioNodesProg();
		var td_osc_num = document.getElementsByClassName("osc_num");

		if(undefined == audioNodesProg) return reject(false);

		for (let i = 0; i < td_osc_num.length; i++) {
		  td_osc_num[i].innerHTML = "";
		}
		for (let i = 0; i < audioNodesProg.length; i++) {
			let arr = audioNodesProg[i].node1.split(" ");
			if ("OscillatorNode" == arr[0]) {
				td_osc_num[i].innerHTML = "osc" + arr[1];
			}
		  if ("AudioBufferSourceNode" == arr[0]) {
				td_osc_num[i].innerHTML = "buf" + arr[1];
			}
		}
		return resolve(true);
	});
}
/**
 * Drawing connections between audio nodes.
 */
function audioNodeLinks(){
	var audioNodes = synth.getAudioNodes();
	var audiograph = document.getElementById("audiograph");
	var ctx = audiograph.getContext("2d");

	var node1_X1;
	var node1_Y1;
	var node2_X2;
	var node2_Y2;

	if(undefined == audioNodes){
		document.getElementById("inform_panel").innerHTML = "Press the music key";
		return;
	}

	audioNodes.forEach((nodes)=> {
		// Node1---------------------------------------------
		let node1 = Nodes_pos.filter((el1) => {
			let search1 = JSON.stringify(el1).indexOf(nodes.node1);
			if (-1 != search1) {
				return search1;
			}
		});
		if(undefined !== node1[0]){
			let node1_posXY = node1[0].posXY.split(",");
			let pos1_X = node1_posXY[0];
			let pos1_Y = node1_posXY[1];

			let el1 = nodes.node1.split(" ");
			let el1_x_y;

			switch(el1[0]) {
			  case "GainNode":
			  	el1_x_y = Nodes_pins.GainNode.out.split(",");
			    break;
			  case "OscillatorNode":
			  	el1_x_y = Nodes_pins.OscillatorNode.out.split(",");
			    break;
			  case "AudioBufferSourceNode":
			  	el1_x_y = Nodes_pins.AudioBufferSourceNode.out.split(",");
			    break;
			  case "StereoPannerNode":
			  	el1_x_y = Nodes_pins.StereoPannerNode.out.split(",");
			    break;
			}
			node1_X1 = parseInt(pos1_X) + parseInt(el1_x_y[0]);
			node1_Y1 = parseInt(pos1_Y) + parseInt(el1_x_y[1]);
		}

		// Node2---------------------------------------------
		let node2 = Nodes_pos.filter((el2) => {
		let nodeName = nodes.node2.replace("/f", "");
			let search2 = JSON.stringify(el2).indexOf(nodeName);
			if (-1 != search2) {
				return search2;
			}
		});
		if(undefined !== node2[0]){
			let node2_posXY = node2[0].posXY.split(",");
			let pos2_X = node2_posXY[0];
			let pos2_Y = node2_posXY[1];

			let el2 = nodes.node1.split(" ");
			let el2_x_y;

			switch(el2[0]) {
			  case "GainNode":
			  	el2_x_y = Nodes_pins.GainNode.in.split(",");
			    break;
			  case "OscillatorNode":
			  	el2_x_y = Nodes_pins.OscillatorNode.f.split(",");
			    break;
			  case "AudioBufferSourceNode":
			  	el2_x_y = Nodes_pins.AudioBufferSourceNode.b.split(",");
			    break;
			  case "StereoPannerNode":
			  	el2_x_y = Nodes_pins.StereoPannerNode.in.split(",");
			    break;
			}
			node2_X2 = parseInt(pos2_X) + parseInt(el2_x_y[0]);
			node2_Y2 = parseInt(pos2_Y) + parseInt(el2_x_y[1]);
		}

		//Draw lines...
		ctxGraph.beginPath();
		ctxGraph.moveTo(node1_X1, node1_Y1);
		ctxGraph.lineTo(node2_X2, node2_Y2);
		ctxGraph.stroke();
	});
	// Another connection.
	ctxGraph.beginPath();
	ctxGraph.moveTo(716, 134);
	ctxGraph.lineTo(716, 190);
	ctxGraph.lineTo(475, 190);
	ctxGraph.lineTo(475, 220);
	ctxGraph.lineTo(5, 220);
	ctxGraph.lineTo(5, 250);
	ctxGraph.stroke();
	//Add comments.
	ctxGraph.font = "11px sans-serif";
	ctxGraph.fillStyle = "black";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText("Oscillograph-Y", 545, 220);
	ctxGraph.fillText("Oscillograph-X", 655, 220);

	return true;
}
/**
 * [osc_or_buf description]
 * @param  {object} node      [description]
 * @param  {string} grid_node [description]
 */
function osc_or_buf(node, grid_node){
	var nameNode = node.split(" ");

	switch(nameNode[0]) {
	  case "OscillatorNode":
	  	OscillatorNode(node, grid_node);
	    break;
	  case "AudioBufferSourceNode":
	  	AudioBufferSourceNode(node, grid_node);
	    break;
	}
}
/**
 * Optimal placement of elements on the canvas
 */
function drawAudioNodes(){
	var audioNodes = synth.getAudioNodes();

	Nodes_pos = [];

	if(undefined == audioNodes){
		document.getElementById("inform_panel").innerHTML = "Press the music key";
		return;
	}

	var nodes = audioNodes.filter((el) => {
		let search = JSON.stringify(el).indexOf("StereoPannerNode");
		if (-1 != search) {
			return search;
		}
	});
	//Place pair of nodes: GainNode/StereoPannerNode.
	if (undefined != nodes && 0 != nodes.length) {
		//Cell[5,2]
		StereoPannerNode(nodes[0].node2, GridNodes[5][2]);
		Nodes_pos.push({"node": nodes[0].node2, "posXY": GridNodes[5][2]});
		//Cell[4,2]
		GainNode(nodes[0].node1, GridNodes[4][2]);
		Nodes_pos.push({"node": nodes[0].node1, "posXY":GridNodes[4][2]});
	}
	//Next nodes...
	nodes = audioNodes.filter((el) => {
		if (el.node2 == nodes[0].node1) {
			return el;
		}
	});

	if(1 == nodes.length) {
		// place to cell [3][2]
		if("GM" == standMidi || 9 == curCh){
			GainNode(nodes[0].node1, GridNodes[3][2], "Ch");
			Nodes_pos.push({"node": nodes[0].node1, "posXY": GridNodes[3][2]});
		}else{
			GraphStructureSF2(); //рисунок структуры SoundFonts
			AudioBufferSourceNode(nodes[0].node1, GridNodes[3][2]);
			Nodes_pos.push({"node": nodes[0].node1, "posXY": GridNodes[3][2]});
		}
	}else if(2 == nodes.length) {
		// place to cell [3][1] and [3][3]
		GainNode(nodes[0].node1, GridNodes[3][1], "Ch");
		Nodes_pos.push({"node": nodes[0].node1, "posXY": GridNodes[3][1]});
		GainNode(nodes[1].node1, GridNodes[3][3], "Ch");
		Nodes_pos.push({"node": nodes[1].node1, "posXY": GridNodes[3][3]});
	}else if (3 == nodes.length) {
		// place to cell [3][1] and [3][2] and [3][3]
		GainNode(nodes[0].node1, GridNodes[3][1], "Ch");
		Nodes_pos.push({"node": nodes[0].node1, "posXY": GridNodes[3][1]});
		GainNode(nodes[1].node1, GridNodes[3][2], "Ch");
		Nodes_pos.push({"node": nodes[1].node1, "posXY": GridNodes[3][2]});
		GainNode(nodes[2].node1, GridNodes[3][3], "Ch");
		Nodes_pos.push({"node": nodes[2].node1, "posXY": GridNodes[3][3]});
	}else if (4 == nodes.length) {
		// place to cell [3][0] and [3][1] and [3][2] and [3][3]
		GainNode(nodes[0].node1, GridNodes[3][0], "Ch");
		Nodes_pos.push({"node": nodes[0].node1, "posXY": GridNodes[3][0]});
		GainNode(nodes[1].node1, GridNodes[3][1], "Ch");
		Nodes_pos.push({"node": nodes[1].node1, "posXY": GridNodes[3][1]});
		GainNode(nodes[2].node1, GridNodes[3][2], "Ch");
		Nodes_pos.push({"node": nodes[2].node1, "posXY": GridNodes[3][2]});
		GainNode(nodes[3].node1, GridNodes[3][3], "Ch");
		Nodes_pos.push({"node": nodes[3].node1, "posXY": GridNodes[3][3]});
	}
	//Next nodes...
	var nodesNext = [];
	nodes.forEach((node)=> {
		audioNodes.filter((el) => {
			if(el.node2 && el.node2 == node.node1) {
				nodesNext.push(el);
			}
		});
	});

	if(1 == nodesNext.length) {
		// place to cell [2][2]
		osc_or_buf(nodesNext[0].node1, GridNodes[2][2]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[2][2]});
	}else if(2 == nodesNext.length) {
		// place to cell [2][1] and [2][3]
		osc_or_buf(nodesNext[0].node1, GridNodes[2][1]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[2][1]});
		osc_or_buf(nodesNext[1].node1, GridNodes[2][3]);
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[2][3]});
	}else if (3 == nodesNext.length) {
		// place to cell [2][1] and [2][2] and [2][3]
		osc_or_buf(nodesNext[0].node1, GridNodes[2][1]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[2][1]});
		osc_or_buf(nodesNext[1].node1, GridNodes[2][2]);
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[2][2]});
		osc_or_buf(nodesNext[2].node1, GridNodes[2][3]);
		Nodes_pos.push({"node": nodesNext[2].node1, "posXY": GridNodes[2][3]});
	}else if (4 == nodesNext.length) {
		// place to cell [2][0] and [2][1] and [2][2] and [2][3]
		osc_or_buf(nodesNext[0].node1, GridNodes[2][0]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[2][0]});
		osc_or_buf(nodesNext[1].node1, GridNodes[2][1]);
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[2][1]});
		osc_or_buf(nodesNext[2].node1, GridNodes[2][2]);
		Nodes_pos.push({"node": nodesNext[2].node1, "posXY": GridNodes[2][2]});
		osc_or_buf(nodesNext[3].node1, GridNodes[2][3]);
		Nodes_pos.push({"node": nodesNext[3].node1, "posXY": GridNodes[2][3]});
	}

	//Next nodes...
	nodesNext = audioNodes.filter((el) => {
		let search = JSON.stringify(el).indexOf("/");
		if (-1 != search) {
			return search;
		}
	});

	if(1 == nodesNext.length) {
		// place to cell [1][1]
		GainNode(nodesNext[0].node1, GridNodes[1][1], "Ch");
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[1][1]});
	}else if(2 == nodesNext.length) {
		// place to cell [1][0] and [1][2]
		GainNode(nodesNext[0].node1, GridNodes[1][0], "Ch");
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[1][0]});
		GainNode(nodesNext[1].node1, GridNodes[1][2], "Ch");
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[1][2]});
	}else if(3 == nodesNext.length) {
		// place to cell [1][1] and [1][2] and [1][3]
		GainNode(nodesNext[0].node1, GridNodes[1][1], "Ch");
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[1][1]});
		GainNode(nodesNext[1].node1, GridNodes[1][2], "Ch");
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[1][2]});
		GainNode(nodesNext[2].node1, GridNodes[1][3], "Ch");
		Nodes_pos.push({"node": nodesNext[2].node1, "posXY": GridNodes[1][3]});
	}

	//Next nodes...
	var nodes = nodesNext;
	nodesNext = [];
	nodes.forEach((node)=> {
		audioNodes.filter((el) => {
			if(el.node2 && el.node2 == node.node1) {
				nodesNext.push(el);
			}
		});
	});

	if(1 == nodesNext.length) {
		// place to cell [0][1]
		osc_or_buf(nodesNext[0].node1, GridNodes[0][1]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[0][1]});
	}else if(2 == nodesNext.length) {
		// place to cell [0][0] and [0][2]
		osc_or_buf(nodesNext[0].node1, GridNodes[0][0]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[0][0]});
		osc_or_buf(nodesNext[1].node1, GridNodes[0][2]);
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[0][2]});
	}else if(3 == nodesNext.length) {
		// place to cell [0][1] and [0][2] and [0][3]
		osc_or_buf(nodesNext[0].node1, GridNodes[0][1]);
		Nodes_pos.push({"node": nodesNext[0].node1, "posXY": GridNodes[0][1]});
		osc_or_buf(nodesNext[1].node1, GridNodes[0][2]);
		Nodes_pos.push({"node": nodesNext[1].node1, "posXY": GridNodes[0][2]});
		osc_or_buf(nodesNext[2].node1, GridNodes[0][3]);
		Nodes_pos.push({"node": nodesNext[2].node1, "posXY": GridNodes[0][3]});
	}
	return true;
}
/**
 * Draw audioNodesCtx of Synthesizer.
 */
function drawAudioNodesCtx(){
	var audioNodesCtx = synth.getAudioNodesCtx();

	var uniqNodes  = [];
	var node1;
	var node2;
	var posX = 10;
	var step = 30;

	audioNodesCtx.forEach((nodes)=> {
		node1 = nodes.node1;
		node2 = nodes.node2;

		let node1Name = (undefined != node1) ?node1.split(" ") :undefined;
		let node2Name = (undefined != node2) ?node2.split(" ") :undefined;

		if (undefined != node1Name && false == uniqNodes.includes(node1)) {
			switch(node1Name[0]) {
			  case "GainNode":
			    GainNode(nodes.node1, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node1, "posXY": posX + ", 225"});
			    posX = posX + 70 + step;
			    break;
			  case "ConvolverNode":
			  	ConvolverNode(nodes.node1, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node1, "posXY": posX + ", 225"});
			    posX = posX + 90 + step;
			    break;
			  case "DynamicsCompressorNode":
			  	DynamicsCompressorNode(nodes.node1, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node1, "posXY": posX + ", 225"});
			    break;
			}
			uniqNodes.push(node1);
		}
		if (undefined != node2Name && false == uniqNodes.includes(node2)) {
			switch(node2Name[0]) {
			  case "GainNode":
			    GainNode(nodes.node2, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node2, "posXY": posX + ", 225"});
			    posX = posX + 70 + step;
			    break;
			  case "ConvolverNode":
			  	ConvolverNode(nodes.node2, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node2, "posXY": posX + ", 225"});
			    posX = posX + 90 + step;
			    break;
			  case "DynamicsCompressorNode":
			  	DynamicsCompressorNode(nodes.node2, posX + ", 225");
			    NodesCtx_pos.push({"node": nodes.node2, "posXY": posX + ", 225"});
			    posX = posX + 150 + step;
			    break;
			  case "AudioDestinationNode":
			  	AudioDestinationNode(nodes.node2, posX + ", 280");
			  	NodesCtx_pos.push({"node": nodes.node2, "posXY": posX + ", 280"});
			    break;
			  case "AnalyserNode":
			  	AnalyserNode(nodes.node2, posX + ", 225");
			  	NodesCtx_pos.push({"node": nodes.node2, "posXY": posX + ", 225"});
			    break;
			}
			uniqNodes.push(node2);
		}
	});
	//Add comments.
	ctxGraph.font = "11px sans-serif";
	ctxGraph.fillStyle = "black";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText("Volume", 45, 255);
	ctxGraph.fillText("Reverb", 265, 255);

	return true;
}
/**
 * [OscillatorNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function OscillatorNode(name, GridNodes){
	let ch = document.getElementById("ch");

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#009688";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,90,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 45+posX, 15+posY);

	ctxGraph.font = "11px sans-serif";

	//Inputs: frequency, detune.
	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("frequency", 7+posX, 30+posY);
	ctxGraph.fillText("detune", 7+posX, 45+posY);
	ctxGraph.fillText("Ch" + ch.value, 60+posX, 45+posY);

	ctxGraph.fillStyle = "#CDDC39";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 40+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(90+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}
/**
 * [GraphStructureSF2 description]
 */
function GraphStructureSF2(){
	ctxGraph.lineWidth = 0.5;
	ctxGraph.fillStyle = "#00D5CE";

	ctxGraph.beginPath();
	ctxGraph.roundRect(20, 20,300,190,[5]);
	ctxGraph.rect(30, 30, 280, 50);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.fillStyle = "#E3E3E3";
	ctxGraph.roundRect(40, 35,80,40,[5]);
	ctxGraph.roundRect(190, 100,120,40,[5]);
	ctxGraph.roundRect(220, 35,80,40,[5]);
	ctxGraph.roundRect(30, 100,120,40,[5]);
	ctxGraph.roundRect(110, 160,120,40,[5]);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.fillStyle = "black";
  ctxGraph.font = "normal 11px arial";

  ctxGraph.fillText("SoundFonts", 140, 15);

	ctxGraph.fillText("preset 0", 60, 50);
	ctxGraph.fillText("keyRange 0", 50, 65);

	ctxGraph.fillText("active zones", 140, 50);

	ctxGraph.fillText("preset n", 240, 50);
	ctxGraph.fillText("keyRange n", 230, 65);

	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(160, 60, 2, 0, 2 * Math.PI);
	ctxGraph.moveTo(170, 60);
	ctxGraph.arc(170, 60, 2, 0, 2 * Math.PI);
	ctxGraph.moveTo(180, 60);
	ctxGraph.arc(180, 60, 2, 0, 2 * Math.PI);
	ctxGraph.fill();

	ctxGraph.fillText("Generators", 60, 125);
	ctxGraph.fillText("Modulators", 220, 125);
	ctxGraph.fillText("Sample", 150, 180);
	ctxGraph.fillText("Buffer", 325, 115);

	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.moveTo(170, 80);
	ctxGraph.lineTo(170, 120);
	ctxGraph.arc(170, 120, 2, 0, 2 * Math.PI);
	ctxGraph.moveTo(150, 120);
	ctxGraph.lineTo(190, 120);

	//стрелка влево
	ctxGraph.moveTo(155, 118);
	ctxGraph.lineTo(150, 120);
	ctxGraph.lineTo(155, 122);

	//стрелка вправо
	ctxGraph.moveTo(185, 118);
	ctxGraph.lineTo(190, 120);
	ctxGraph.lineTo(185, 122);

	//стрелка влево
	ctxGraph.moveTo(235, 178);
	ctxGraph.lineTo(230, 180);
	ctxGraph.lineTo(235, 182);

	//стрелка вправо
	ctxGraph.moveTo(105, 178);
	ctxGraph.lineTo(110, 180);
	ctxGraph.lineTo(105, 182);

	ctxGraph.moveTo(80, 140);
	ctxGraph.lineTo(80, 180);
	ctxGraph.lineTo(110, 180);

	ctxGraph.moveTo(260, 140);
	ctxGraph.lineTo(260, 180);
	ctxGraph.lineTo(230, 180);

	ctxGraph.moveTo(320, 120);
	ctxGraph.lineTo(360, 120);

	ctxGraph.stroke();

}

/**
 * [AudioBufferSourceNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function AudioBufferSourceNode(name, GridNodes){
	let ch = document.getElementById("ch");

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#905096";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,90,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("AudioBufferSourceNode", "AudioBufSrc"), 45+posX, 15+posY);

	ctxGraph.font = "11px sans-serif";

	//Inputs: playbackRate, detune.
	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("playbackRate", 7+posX, 30+posY);
	ctxGraph.fillText("detune", 7+posX, 45+posY);
	ctxGraph.fillText("Ch" + ch.value, 65+posX, 45+posY);

	ctxGraph.fillStyle = "#CDDC39";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 40+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(90+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}


/**
 * [GainNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function GainNode(name, GridNodes, Ch) {

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#3F51B5";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,70,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 35+posX, 15+posY);

	ctxGraph.font = "11px sans-serif";

	//Inputs: gain.
	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("gain", 7+posX, 45+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#CDDC39";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 40+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(70+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#CFD8DC";
	if(Ch) ctxGraph.fillText("Ch" + ch.value, 40+posX, 45+posY);

}
/**
 * [StereoPannerNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function StereoPannerNode(name, GridNodes) {

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#2196F3";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,110,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 55+posX, 15+posY);

	ctxGraph.font = "11px sans-serif";

	//Inputs: gain.
	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("pan", 7+posX, 45+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#CDDC39";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 42+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(110+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}
/**
 * [ConvolverNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function ConvolverNode(name, GridNodes) {
	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#2196F3";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,90,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 45+posX, 15+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(90+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}
/**
 * [DynamicsCompressorNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function DynamicsCompressorNode(name, GridNodes) {

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#2196F3";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,150,80,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 75+posX, 15+posY);

	ctxGraph.font = "11px sans-serif";

	//Inputs:
	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("threshold", 7+posX, 35+posY);

	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("knee", 7+posX, 45+posY);

	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("ratio", 7+posX, 55+posY);

	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("attack", 7+posX, 65+posY);

	ctxGraph.fillStyle = "#CFD8DC";
	ctxGraph.textAlign = "left";
	ctxGraph.fillText("release", 7+posX, 75+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 20+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#CDDC39";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 32+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 42+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 52+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 62+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 72+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(150+posX, 40+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}
/**
 * [AudioDestinationNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function AudioDestinationNode(name, GridNodes) {
	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#37474F";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,190,25,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 95+posX, 15+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 12+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}
/**
 * [AnalyserNode description]
 * @param string name      Name of audioNode
 * @param string GridNodes Position X,Y
 */
function AnalyserNode(name, GridNodes) {

	GridNodes = GridNodes.split(",");

	let posX = parseInt(GridNodes[0]);
	let posY = parseInt(GridNodes[1]);

	ctxGraph.fillStyle = "#00BCD4";

	ctxGraph.beginPath();
	ctxGraph.roundRect(posX, posY,90,50,[5]);
	ctxGraph.fill();

	ctxGraph.font = "12px sans-serif";

	//Name audioNode.
	ctxGraph.fillStyle = "white";
	ctxGraph.textAlign = "center";
	ctxGraph.fillText(name.replace("Node", ""), 45+posX, 15+posY);

	ctxGraph.fillStyle = "#4CAF50";
	ctxGraph.lineWidth = 1;
	ctxGraph.strokeStyle = "#000000";

	ctxGraph.beginPath();
	ctxGraph.arc(posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();

	ctxGraph.fillStyle = "#E91E63";

	ctxGraph.beginPath();
	ctxGraph.arc(90+posX, 25+posY, 4, 0, 2 * Math.PI);
	ctxGraph.fill();
	ctxGraph.stroke();
}