//Tabelle der MIDI-Nummern zur normalen Notation let midiNotes = { "21": "A0", "22": "A#0", "23": "B0", "24": "C1", "25": "C#1", "26": "D1", "27": "D#1", "28": "E1", "29": "F1", "30": "F#1", "31": "G1", "32": "G#1", "33": "A1", "34": "A#1", "35": "B1", "36": "C2", "37": "C#2", "38": "D2", "39": "D#2", "40": "E2", "41": "F2", "42": "F#2", "43": "G2", "44": "G#2", "45": "A2", "46": "A#2", "47": "B2", "48": "C3", "49": "C#3", "50": "D3", "51": "D#3", "52": "E3", "53": "F3", "54": "F#3", "55": "G3", "56": "G#3", "57": "A3", "58": "A#3", "59": "B3", "60": "C4", "61": "C#4", "62": "D4", "63": "D#4", "64": "E4", "65": "F4", "66": "F#4", "67": "G4", "68": "G#4", "69": "A4", "70": "A#4", "71": "B4", "72": "C5", "73": "C#5", "74": "D5", "75": "D#5", "76": "E5", "77": "F5", "78": "F#5", "79": "G5", "80": "G#5", "81": "A5", "82": "A#5", "83": "B5", "84": "C6", "85": "C#6", "86": "D6", "87": "D#6", "88": "E6", "89": "F6", "90": "F#6", "91": "G6", "92": "G#6", "93": "A6", "94": "A#6", "95": "B6", "96": "C7", "97": "C#7", "98": "D7", "99": "D#7", "100": "E7", "101": "F7", "102": "F#7", "103": "G7", "104": "G#7", "105": "A7", "106": "A#7", "107": "B7", "108": "C8", }; //Die Rückrichtung davon let reverseMidiNotes = {}; Object.keys(midiNotes).forEach(e => { reverseMidiNotes[midiNotes[e]] = e; }); //Tabelle von Tonvorräten der Instrumente //an dieser Stellen müssen auch weitere Instrumente eingefügt werden let tonvorrat = { "1097": { "1": "F1", "2": "Fis1", "3": "G1", "4": "Gis1", "5": "A1", "6": "Ais1", "7": "H1", "8": "C", "9": "Cis", "10": "D", "11": "Dis", "12": "E", "13": "F", "14": "Fis", "15": "G", "16": "Gis", "17": "A", "18": "Ais", "19": "H", "20": "c", "21": "cis", "22": "d", "23": "dis", "24": "e", "25": "f", "26": "fis", "27": "g", "28": "gis", "29": "a", "30": "ais", "31": "h", "32": "c1", "33": "cis1", "34": "d1", "35": "dis1", "36": "e1", "37": "f1", "38": "fis1", "39": "g1", "40": "gis1", "41": "a1", "42": "ais1", "43": "h1", "44": "c2", "45": "cis2", "46": "d2", "47": "dis2", "48": "e2", "49": "f2", "50": "fis2", "51": "g2", "52": "gis2", "53": "a2", "54": "ais2", "55": "h2", "56": "c3", "57": "cis3", "58": "d3", "59": "dis3", "60": "e3", "61": "f3", "62": "fis3", "63": "g3", "64": "gis3", "65": "a3", "66": "ais3", "67": "h3", "68": "c4" }, "0082": { "2": "G1", "3": "A1", "4": "B1", "5": "H1", "6": "C", "7": "Cis", "8": "D", "9": "Dis", "10": "E", "11": "F", "12": "Fis", "13": "G", "14": "Gis", "15": "A", "16": "B", "17": "H", "18": "c", "19": "cis", "20": "d", "21": "dis", "22": "e", "23": "f", "24": "fis", "25": "g", "26": "gis", "27": "a", "28": "b", "29": "h", "30": "c1", "31": "cis1", "32": "d1", "33": "dis1", "34": "e1", "35": "f1", "36": "fis1", "37": "g1", "38": "gis1", "39": "a1", "40": "b1", "41": "h1", "42": "c2", "43": "cis2", "44": "d2", "45": "dis2", "46": "e2", "47": "f2", "48": "fis2", "49": "g2", "50": "gis2", "51": "a2", "52": "b2", "53": "h2", "54": "c3" }, "0012": { "1": "C", "2": "Cis", "3": "D", "4": "Dis", "5": "E", "6": "F", "7": "Fis", "8": "G", "9": "Gis", "10": "A", "11": "B", "12": "H", "13": "c", "14": "cis", "15": "d", "16": "dis", "17": "e", "18": "f", "19": "fis", "20": "g", "21": "gis", "22": "a", "23": "b", "24": "h", "25": "c1", "26": "cis1", "27": "d1", "28": "dis1", "29": "e1", "30": "f1", "31": "fis1", "32": "g1", "33": "gis1", "34": "a1", "35": "b1", "36": "h1", "37": "c2", "38": "cis2", "39": "d2", "40": "dis2", "41": "e2", "42": "f2", "43": "fis2", "44": "g2", "45": "gis2", "46": "a2", "47": "b2", "48": "h2", "49": "c3" }, "3191": { "1": "C1", "1": "C1", "2": "Cis1", "2": "Cis1", "3": "D1", "3": "D1", "4": "Dis1", "4": "Dis1", "5": "E1", "5": "E1", "6": "F1", "6": "F1", "6": "F1", "7": "Fis1", "7": "Fis1", "7": "Fis1", "8": "G1", "8": "G1", "8": "G1", "9": "Gis1", "9": "Gis1", "9": "Gis1", "10": "A1", "10": "A1", "10": "A1", "11": "B1", "11": "B1", "11": "B1", "12": "H1", "12": "H1", "12": "H1", "13": "C", "13": "C", "13": "C", "14": "Cis ", "14": "Cis", "14": "Cis", "15": "D", "15": "D", "15": "D", "16": "Dis", "16": "Dis", "16": "Dis", "17": "E", "17": "E", "17": "E", "18": "F", "18": "F", "18": "F", "19": "Fis", "19": "Fis", "19": "Fis", "20": "G", "20": "G", "20": "G", "21": "Gis", "21": "Gis ", "21": "Gis", "22": "A", "22": "A", "22": "A", "23": "B", "23": "B", "23": "B", "24": "H", "24": "H ", "24": "H", "25": "c", "25": "c", "25": "c", "26": "cis", "26": "cis", "26": "cis", "27": "d", "27": "d", "27": "d", "28": "dis", "28": "dis", "28": "dis", "29": "e", "29": "e", "29": "e", "30": "f", "30": "f", "30": "f", "31": "fis", "31": "fis", "31": "fis", "32": "g", "32": "g", "32": "g", "33": "gis", "33": "gis", "33": "gis", "34": "a", "34": "a", "34": "a", "35": "b", "35": "b", "35": "b", "36": "h", "36": "h", "36": "h", "37": "c1", "37": "c1", "37": "c1", "38": "cis1", "38": "cis1", "38": "cis1", "39": "d1", "39": "d1", "39": "d1", "40": "dis1", "40": "dis1", "40": "dis1", "41": "e1", "41": "e1", "41": "e1", "42": "f1", "42": "f1", "42": "f1", "43": "fis1", "43": "fis1", "43": "fis1", "44": "g1", "44": "g1", "44": "g1", "45": "gis1", "45": "gis1", "45": "gis1", "46": "a1", "46": "a1", "46": "a1", "47": "b1", "47": "b1", "47": "b1", "48": "h1", "48": "h1", "48": "h1", "49": "c2", "49": "c2", "49": "c2", "50": "cis2", "50": "cis2", "50": "cis2", "51": "d2", "51": "d2", "51": "d2", "52": "dis2", "52": "dis2", "52": "dis2", "53": "e2", "53": "e2", "53": "e2", "54": "f2", "54": "f2", "54": "f2", "55": "fis2", "55": "fis2", "55": "fis2", "56": "g2", "56": "g2", "56": "g2", "57": "gis2", "57": "gis2", "57": "gis2", "58": "a2", "58": "a2", "58": "a2", "59": "b2", "59": "b2", "59": "b2", "60": "h2", "60": "h2", "60": "h2", "61": "c3", "61": "c3", "61": "c3", "62": "cis3", "62": "cis3", "62": "cis3", "63": "d3", "63": "d3", "63": "d3", "64": "dis3", "64": "dis3", "64": "dis3", "65": "e3", "65": "e3", "65": "e3", "66": "f3", "66": "f3", "66": "f3", "67": "fis3", "67": "fis3", "67": "fis3", "68": "g3", "68": "g3", "68": "g3", "69": "gis3", "69": "gis3", "69": "gis3", "70": "a3", "70": "a3", "70": "a3", "71": "b3", "71": "b3", "71": "b3", "72": "h3", "72": "h3", "72": "h3", "73": "c4", "73": "c4", "73": "c4", "74": "cis4", "74": "cis4", "74": "cis4", "75": "d4", "75": "d4", "75": "d4", "76": "dis4", "76": "dis4", "76": "dis4", "77": "e4", "77": "e4", "77": "e4", "78": "f4", "78": "f4", "78": "f4" } }; //Übersetzung der verschiedenen Notationen von Noten let dictToneNames = { "C2": "C0", "Cis2": "C#0", "D2": "D0", "Dis2": "D#0", "E2": "E0", "F2": "F0", "Fis2": "F#0", "G2": "G0", "Gis2": "G#0", "A2": "A0", "Ais2": "A#0", "B2": "A#0", "H2": "B0", "C1": "C1", "Cis1": "C#1", "D1": "D1", "Dis1": "D#1", "E1": "E1", "F1": "F1", "Fis1": "F#1", "G1": "G1", "Gis1": "G#1", "A1": "A1", "Ais1": "A#1", "B1": "A#1", "H1": "B1", "C": "C2", "Cis": "C#2", "D": "D2", "Dis": "D#2", "E": "E2", "F": "F2", "Fis": "F#2", "G": "G2", "Gis": "G#2", "A": "A2", "Ais": "A#2", "B": "A#2", "H": "B2", "c": "C3", "cis": "C#3", "d": "D3", "dis": "D#3", "e": "E3", "f": "F3", "fis": "F#3", "g": "G3", "gis": "G#3", "a": "A3", "ais": "A#3", "b": "A#3", "h": "B3", "c1": "C4", "cis1": "C#4", "d1": "D4", "dis1": "D#4", "e1": "E4", "f1": "F4", "fis1": "F#4", "g1": "G4", "gis1": "G#4", "a1": "A4", "ais1": "A#4", "b1": "A#4", "h1": "B4", "c2": "C5", "cis2": "C#5", "d2": "D5", "dis2": "D#5", "e2": "E5", "f2": "F5", "fis2": "F#5", "g2": "G5", "gis2": "G#5", "a2": "A5", "ais2": "A#5", "b2": "A#5", "h2": "B5", "c3": "C6", "cis3": "C#6", "d3": "D6", "dis3": "D#6", "e3": "E6", "f3": "F6", "fis3": "F#6", "g3": "G6", "gis3": "G#6", "a3": "A6", "b3": "A#6", "ais3": "A#6", "h3": "B6", "c4": "C7", "cis4": "C#7", "d4": "D7", "dis4": "D#7", "e4": "E7", "f4": "F7", "fis4": "F#7", "g4": "G7", "gis4": "G#7", "a4": "A7", "b4": "A#7", "ais4": "A#7", "h4": "B7", "c5": "C8", "cis5": "C#8", "d5": "D8" }; class Keyboard { constructor(parent, instrumentName, files) { this.parent = parent; //hieran wird die Instanz angehangen this.instrumentName = instrumentName; //der Name der Instruments this.files = files; this.id = instrumentName + "keyboardVis"; this.midiActive = false; this.velocity = true; this.notes = {}; //Zuordnung der Tonnamen zu den Dateinamen der Samples this.tastenNummern = {}; //Zuordnung von Tastennummer zu Tonname //die Tasten sind von der tiefsten bis zur höchsten Taste durchnummeriert this.audioContext = null; //Context für Kompressoren und Filter //KeyCodes der PC-Tastatur this.keys = [89, 83, 88, 68, 67, 86, 71, 66, 72, 78, 74, 77, 81, 50, 87, 51, 69, 82, 53, 84, 54, 90, 55, 85]; /* this.startMidiNote = "nA"; this.octaveRange = [0, 6]; this.maxOctave = 0; this.minOctave = 99; this.octaveSteps = 1; this.blackKeys = [1, 3, 6, 8, 10]; to be deleted */ //Erstellung der Tonreinfolge let tmpTonvorrat = tonvorrat[this.instrumentName.replace("401", "")]; for (let tastenNummer of Object.keys(tmpTonvorrat)) { let dictTone = tmpTonvorrat[tastenNummer.toString()]; //Übersetzung des Tonnamens this.tastenNummern[tastenNummer.toString()] = dictToneNames[dictTone]; console.log("HERE", tastenNummer, dictTone, dictToneNames[dictTone]); } console.log(this.tastenNummern); //Erstellung der Zuordnung der Tonnamen zu den Sampledateien for (let file of this.files.values()) { let soundFile = file; let split = soundFile.replace(".mp3", "").split("_"); /* das Rautenzeichen darf in Dateinamen nicht vorkommen, weil die Browser damit nicht klar kommen, deshalb habe ich es durch 'hash' ersetzt */ let tonename = split[1].replace("hash", "#"); let noteNumber = parseInt(reverseMidiNotes[tonename]); this.notes[tonename] = { "file": file, "number": noteNumber }; } console.log(this.notes); /*this.octaveRange = [this.minOctave, this.maxOctave]; to be deleted*/ this.init(); } //Installation des Kompressors createAduioContext() { let AudioContext = window.AudioContext || window.webkitAudioContext; this.audioContext = new AudioContext(); this.compressor = this.audioContext.createDynamicsCompressor(); this.compressor.threshold.setValueAtTime(-7, this.audioContext.currentTime); this.compressor.knee.setValueAtTime(0, this.audioContext.currentTime); this.compressor.ratio.setValueAtTime(20, this.audioContext.currentTime); this.compressor.attack.setValueAtTime(0.005, this.audioContext.currentTime); this.compressor.release.setValueAtTime(0.5, this.audioContext.currentTime); this.compressor.connect(this.audioContext.destination); } //Initialisierung der Instanz und der Darstellung init() { $("#" + this.id + "Options").remove(); $(this.parent).append("
\
\ \
\
"); //$("#startMidiNoteOptions").css("display", this.midiActive ? "inline-block" : "none"); to be deleted $("#" + this.id + "keyboardWrapper").remove(); $(this.parent).append("
"); //Zuorndung von Tastatur-Tasten zu Tönen this.keyToTone = {}; //Zuorndung von MIDI-Nummern zu Tönen this.midiToTone = {}; this.tones = {}; this.tonesSources = {}; this.tonesGains = {}; this.keyKeypressed = {}; this.render(); let margin = 2; //Berechnung der Breite der Klaviatur let width = Math.floor($(this.parent).find(".keyboardVisWrapper").first().width() / (Object.keys(this.notes).filter(e => !e.includes("#")).length + 2)) - margin; //styling $(".key").css("width", (width - margin) + "px"); $(".key.black").css("width", (2 * width / 3 - margin) + "px"); $(".key").css("margin-right", margin + "px"); $(".key.black").css("margin-left", (-1 * width / 3) + "px"); //Initialisierung der EventListeners der Maus $(".key").on("mousedown", this.hitKey.bind(this)); $(".key").on("mouseup", this.hitReleaseKey.bind(this)); //Der Schalter für die Anschlagsdynamik $("#" + this.id + "velocityButton").find(".circle").first().css("background-color", "green"); $("#" + this.id + "velocityButton").on("click", this.changeVelocity.bind(this)); //Schalter für die Verschiebung der Oktaven $("#" + this.id + "octaveButtonLeft").on("click", () => this.octaveChange(-1)); $("#" + this.id + "octaveButtonRight").on("click", () => this.octaveChange(1)); /*$("#" + this.id + "startMidiNoteInput").on("change", () => { to be deleted this.setStartMidiNote(parseInt($("#" + this.id + "startMidiNoteInput").val())); });*/ } /*setStartMidiNote(startMidiNote) { to be deleted this.startMidiNote = startMidiNote; $("#" + this.id + "startMidiNoteInput").val(startMidiNote); this.init(); }*/ //Funktion zum Umschalten der Anschlagsdynamik changeVelocity() { this.velocity = !this.velocity; if (this.velocity) { $("#" + this.id + "velocityButton").find(".circle").first().css("background-color", "green"); } else { $("#" + this.id + "velocityButton").find(".circle").first().css("background-color", "red"); } } /*Deaktivieren von MIDI im Falle eines Fehlers bisher Unterstützt nur Chrome den MIDI-Zugriff, alle anderen Browser werfen Fehler*/ onMIDIFailure() { this.midiActive = false; } //Binden des MIDI EventListeners onMIDISuccess(midiAccess) { /*$("#startMidiNoteOptions").css("display", "inline-block"); to be deleted*/ this.midiActive = true; for (var input of midiAccess.inputs.values()) input.onmidimessage = this.getMIDIMessage.bind(this); } //EventListener für den MIDI Input getMIDIMessage(midiMessage) { if (midiMessage.data[0] === 144) { //Beim Herunterdrücken der Taste den passenden Ton abspielen if (this.midiToTone.hasOwnProperty(midiMessage.data[1].toString())) { let tonename = this.midiToTone[midiMessage.data[1].toString()]; this.playKey(tonename, this.velocity ? midiMessage.data[2] / 127 : 1); } } else if (midiMessage.data[0] === 128) { //Beim Loslassen der Taste den passenden Ton stoppen if (this.midiToTone.hasOwnProperty(midiMessage.data[1].toString())) { let tonename = this.midiToTone[midiMessage.data[1].toString()]; this.stopKey(tonename); } } /* let $focused = $(':focus'); if ($focused.attr("id") === this.id + "startMidiNoteInput") { this.setStartMidiNote(midiMessage.data[1]); $("#" + this.id).focus(); } to be deleted */ } //Funktion für die Erstelluung von JQuery Strings für die Tasten im Frontend createKey(tonename, midiNote, keyIndex, black = false) { return "
" + /*String.fromCharCode(charCode) +*/ "
" + /*keyname.replace("hash", "#") + octave +*/ "
"; } //EventListener für das Drücken von Tastatur-Tasten pressKey(e) { let keyStr = e.which.toString(); if (this.keyKeypressed[keyStr] === true) { return; //Wenn die Taste bereits gedrückt ist, soll nichts geschehen } else { if (this.keyToTone.hasOwnProperty(keyStr)) { //Abspielen es Tons, wenn die Taste im Tonvorrat vorhanden ist let tonename = this.keyToTone[keyStr]; console.log(keyStr, tonename); this.playKey(tonename, 1.0); } else if (parseInt(keyStr) === 38 || parseInt(keyStr) === 39) { //Tasten rechts und oben für das Erhöhen der Oktave this.octaveChange(1); } else if (parseInt(keyStr) === 40 || parseInt(keyStr) === 37) { //Tasten links und unten für das Verringern der Oktave this.octaveChange(-1); } //Hash für den Zustand von Tasten mit true beschreiben this.keyKeypressed[keyStr] = true; } } //EventListener für das Loslassen der Tastatur-Tasten releaseKey(e) { let keyStr = e.which.toString(); if (this.keyToTone.hasOwnProperty(keyStr)) { //Das Abspielen des Tons stoppen, wenn die Taste losgelassen wird let tonename = this.keyToTone[keyStr]; this.stopKey(tonename); } //Hash für den Zustand von Tasten mit false beschreiben this.keyKeypressed[keyStr] = false; } //Funktion für das Binden der KeyListener von außen bindKeys() { $("body").on("keydown", this.pressKey.bind(this)); $("body").on("keyup", this.releaseKey.bind(this)); } //Funktion für das Entbinden der KeyListener von außen unbindKeys() { $("body").off("keydown"); $("body").off("keyup"); } //Funktion für das Binden der MIDI-Listener bindMIDI() { try { navigator.requestMIDIAccess().then(this.onMIDISuccess.bind(this), this.onMIDIFailure.bind(this)); } catch (e) { console.log(e); } } //Funktion für das Entbinden der MIDI-Listener unbindMIDI() { try { navigator.requestMIDIAccess().then(() => {}, () => {}); } catch (e) { console.log(e); } } //EventListener für das Klicken der Tasten mit der Maus hitKey(e) { let tonename = $(e.target).attr("tonename"); let y = e.pageY - $(e.target).offset().top; /*Abspielen des Tons, Die Lautstärke des Tons wird zur Simulation der Anschlagsdynamik anhand der relativen y-Position berechnet*/ let volume = this.velocity ? Math.min(y / $(e.target).height(), 1.0) : 1.0; console.log(tonename); this.playKey(tonename, volume); } //EventListener für das Loslassen der Taste per Maus hitReleaseKey(e) { let tonename = $(e.target).attr("tonename"); /*let y = e.pageY - $(e.target).offset().top; to be deleted???*/ this.stopKey(tonename); } /*octaveChange(add) { //braucht Überarbeitung if (add > 0) { this.octaveRange[0] = Math.min(this.octaveRange[0] + 2, this.maxOctave - this.octaveSteps); this.octaveRange[1] = Math.min(this.octaveRange[1] + 2, this.maxOctave); } else if (add < 0) { this.octaveRange[0] = Math.max(this.octaveRange[0] - 2, this.minOctave); this.octaveRange[1] = Math.max(this.octaveRange[1] - 2, this.minOctave + this.octaveSteps); } this.init(); }*/ //Abspielen des Tons, die Lautstärke wird als Parameter übergeben playKey(tonename, volume = 1.0) { if (this.audioContext === null) { this.createAduioContext(); } if (this.tones.hasOwnProperty(tonename)) { let audio = this.tones[tonename]; //Abfragen des Audios setTimeout(function() { //Abspielen des Audios audio.currentTime = 0; audio.volume = volume; audio.play(); }, 0); //die gedrückte oder geklickte Taste selektieren let keySel = $(".key[tonename='" + tonename + "']"); //Styling der gedrückten Taste keySel.addClass("active"); let top; if (keySel.attr("origTop") === undefined) { top = parseInt(keySel.css("top").replace("px", "")); keySel.attr("origTop", top); } else { top = parseInt(keySel.attr("origTop")); } let left if (keySel.attr("origTop") === undefined) { left = parseInt(keySel.css("left").replace("px", "")); keySel.attr("origLeft", topleft); } else { left = parseInt(keySel.attr("origLeft")); } //Die gedrückte Taste wird um die berechneten Pixel nach oben und links verschoben keySel.css("top", top + 4 + "px"); keySel.css("left", left + 1 + "px"); } } //Stoppen der Tonwiedergabe stopKey(tonename, volume = 1.0) { if (this.tones.hasOwnProperty(tonename)) { let audio = this.tones[tonename]; //let gainNode = this.tonesGains[tonename]; /*Den Ton langsam ausfaden, damit eine Dämpfung oder Abschwingen der Saite simuliert werden kann*/ let fadeAudio = setInterval(function() { // Only fade if past the fade out point or not at zero already if (audio.volume > 0.01) { audio.volume -= 0.01; } else { // When volume at zero stop all the intervalling clearInterval(fadeAudio); } //gainNode.gain.setValueAtTime(0.0001, this.audioContext.currentTime); }.bind(this), 20) /*Da das Abklingen mit meiner Fade-Methode ein hörbares Knacken beim faden zu hören ist, probierten Dominik und ich mit Gains herum, dies gilt es weiter zu vertiefen */ //gainNode.gain.setValueAtTime(gainNode.gain.value, this.audioContext.currentTime); //gainNode.gain.setValueAtTime(0.0001, this.audioContext.currentTime+1); //gainNode.gain.exponentialRampToValueAtTime(0.0001, this.audioContext.currentTime + 0.03); //gainNode.gain.linearRampToValueAtTime(0.0001, this.audioContext.currentTime + 1); //gainNode.gain.linearRampToValueAtTime(0, audioCtx.currentTime + 2); //Die gespielte Taste im Frontend selektieren und anschließend stylen let keySel = $(".key[tonename='" + tonename + "']"); let top; top = parseInt(keySel.attr("origTop")); let left left = parseInt(keySel.attr("origLeft")); keySel.removeClass("active"); keySel.css("top", top + "px"); keySel.css("left", left + "px"); } } render() { this.keyCount = 0; //Für jede Taste im Tonvorrat eine Taste und Audio erzeugen for (let tastenNummer of Object.keys(this.tastenNummern)) { let tonename = this.tastenNummern[tastenNummer]; let midiNote = reverseMidiNotes[tonename]; /*Beschreibung der Computer-Tastatur mit den entsprechenden Tonnamen 36 ist die erste für uns nutzbare MIDI-Nummer für ein C*/ if (this.keys[parseInt(midiNote)-36]) { this.keyToTone[this.keys[parseInt(midiNote)-36].toString()] = tonename; } console.log(midiNote, tastenNummer, this.keys[parseInt(midiNote)-36], parseInt(midiNote)-36, tonename); this.midiToTone[midiNote] = tonename; let file = undefined; if (this.notes.hasOwnProperty(tonename)) { file = this.notes[tonename].file; //Aus der Sample-Datei ein Audio-Objekt erzeugen this.tones[tonename] = new Audio(file); this.tones[tonename].preload = 'auto'; } //Tasten im Frontend erzeugen und anhängen if (tonename.includes("#")) { //schwarte Tasten $("#" + this.id + "keyboardWrapper").append(this.createKey(tonename, midiNote, this.keyCount, true)); } else { $("#" + this.id + "keyboardWrapper").append(this.createKey(tonename, midiNote, this.keyCount)); } this.keyCount++; } console.log(this.keyToTone); } }