//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 "