So erstellen Sie eine Klaviertastatur mit Vanilla JavaScript

Das Erstellen einer spielbaren Klaviertastatur kann eine großartige Möglichkeit sein, eine Programmiersprache zu lernen (abgesehen davon, dass es jede Menge Spaß macht). Dieses Tutorial zeigt Ihnen, wie Sie eines mit Vanille-JavaScript codieren, ohne dass externe Bibliotheken oder Frameworks erforderlich sind.

Hier ist die JavaScript-Klaviertastatur, die ich erstellt habe, wenn Sie zuerst das Endprodukt überprüfen möchten.

In diesem Lernprogramm wird davon ausgegangen, dass Sie über grundlegende Kenntnisse in JavaScript wie Funktionen und Ereignisbehandlung sowie über Kenntnisse in HTML und CSS verfügen. Ansonsten ist es absolut anfängerfreundlich und richtet sich an diejenigen, die ihre JavaScript-Kenntnisse durch projektbasiertes Lernen verbessern möchten (oder einfach nur ein cooles Projekt machen möchten!).

Die Klaviertastatur, die wir für dieses Projekt herstellen, basiert auf der dynamisch erzeugten synthetischen Tastatur von Keith William Horwood. Wir werden die Anzahl der verfügbaren Tasten auf 4 Oktaven erweitern und neue Tastenkombinationen festlegen.

Obwohl sein Keyboard Klänge von anderen Instrumenten spielen kann, werden wir die Dinge einfach halten und einfach beim Klavier bleiben.

Hier sind die Schritte, die wir unternehmen werden, um dieses Projekt anzugehen:

1. Holen Sie sich Arbeitsdateien

2. Richten Sie Tastenkombinationen ein

3. Tastatur generieren

4. Drücken Sie die Taste

Lass uns anfangen!

1. Arbeitsdateien abrufen

In diesem Tutorial werden die folgenden Dateien verwendet:

· Audiosynth.js

· PlayKeyboard.js

Wie bereits erwähnt, werden wir unsere Klaviertastatur auf die von Keith stützen. Natürlich werden wir auch einen Teil seines Codes ausleihen, den er freundlicherweise mit audiosynth.js genehmigt hat.

Wir integrieren audiosynth.js in playKeyboard.js (meine modifizierte Version eines Teils von Keiths Code), das unser gesamtes JavaScript verarbeitet. Dieses Tutorial enthält in den folgenden Abschnitten eine ausführliche Erläuterung der wichtigsten Punkte, wie der Code in dieser Datei eine voll funktionsfähige Klaviertastatur erstellt.

Wir lassen die Datei audiosynth.js unberührt, da sie allein für die Klangerzeugung verantwortlich ist.

Der Code in dieser Datei unterscheidet diese Klaviertastatur von anderen online gefundenen, indem Javascript verwendet wird, um dynamisch den entsprechenden Klang zu erzeugen, wenn der Benutzer eine Taste drückt. Somit muss der Code keine externen Audiodateien laden.

Keith gibt auf seiner Website bereits eine Erklärung zur Funktionsweise der Klangerzeugung, sodass wir hier nicht auf die Details eingehen werden.

Kurz gesagt, es geht darum, die Math.sin()Funktion in JS zu verwenden, um sinusförmige Wellenformen zu erstellen und diese so zu transformieren, dass sie durch ausgefallene Mathematik eher wie echte Instrumente klingen.

Erstellen Sie eine Index-HTML-Datei und verknüpfen Sie sie mit den JS-Dateien im Header:

Im Körper können wir ein leeres Element erstellen , das als Tastaturcontainer dient:

Wir geben ihm einen ID-Namen, damit wir später darauf verweisen können, wenn wir die Tastatur mit JS erstellen. Wir können unseren JS-Code ausführen, indem wir ihn auch im Body aufrufen:

playKeyboard()

Wir verwenden playKeyboard.js als eine große Funktion. Es wird ausgeführt, sobald der Browser diese Codezeile erreicht und eine voll funktionsfähige Tastatur im Element mit generiert

id = “keyboard”.

Die ersten Zeilen von playKeyboard.js richten sich nach der Funktionalität für mobile Geräte (optional) und erstellen ein neues AudioSynth()Objekt. Wir verwenden dieses Objekt, um die Methoden von audiosynth.js aufzurufen, mit denen wir zuvor verknüpft haben. Wir verwenden zu Beginn eine dieser Methoden, um die Lautstärke für den Sound einzustellen.

In Zeile 11 setzen wir die Position von mittlerem C auf die 4. Oktave.

2. Richten Sie die Tastenkombinationen ein

Bevor wir die Tastatur generieren, sollten wir unsere Tastenkombinationen einrichten, da sie bestimmen, wie viele Tasten generiert werden sollen.

Ich wollte ursprünglich versuchen, die Eröffnungsnoten von 'Für Elise' zu spielen, also habe ich einen Bereich von 4 Oktaven für insgesamt 48 Schwarz-Weiß-Tasten gewählt. Dies erforderte fast jede Taste auf meiner (PC-) Tastatur, und Sie können gerne weniger einschließen.

Ein Hinweis zur Warnung: Ich habe nicht die besten Tastenkombinationen, sodass sie sich möglicherweise nicht intuitiv anfühlen, wenn Sie tatsächlich versuchen zu spielen. Vielleicht ist dies der Preis für den Versuch, eine 4-Oktaven-Tastatur zu erstellen.

Um die Tastenkombinationen einzurichten, erstellen Sie zunächst ein Objekt, das den Tastencode als Tasten und die zu spielende Note als Tastenwerte verwendet (Startzeile 15):

var keyboard = { /* ~ */ 192: 'C,-2', /* 1 */ 49: 'C#,-2', /* 2 */ 50: 'D,-2', /* 3 */ 51: 'D#,-2', //...and the rest of the keys } 

Die Kommentare bezeichnen die Tasten, die ein Benutzer auf einer Computertastatur drücken kann. Wenn ein Benutzer die Tilde-Taste drückt, lautet der entsprechende Schlüsselcode 192. Sie können den Schlüsselcode mit einem Tool wie keycode.info abrufen.

Der Schlüsselwert ist die Note, die im Format 'Note, Oktavmodifikator' gespielt und geschrieben werden soll, wobei der Oktavmodifikator die relative Oktavposition von der Oktave mit mittlerem C darstellt. Beispielsweise ist 'C, -2' die C-Note 2 Oktaven unter dem mittleren C.

Beachten Sie, dass es keine "flachen" Schlüssel gibt. Jede Note wird durch ein "scharf" dargestellt.

Um unsere Klaviertastatur funktionsfähig zu machen, müssen wir eine Reverse-Lookup-Tabelle erstellen, in der wir die key: valuePaare so umschalten, dass die zu spielende Note zur Taste und der Schlüsselcode zum Wert wird.

Wir brauchen eine solche Tabelle, weil wir die Noten durchlaufen wollen, um unsere Tastatur einfach zu generieren.

Hier kann es schwierig werden: Wir benötigen tatsächlich zwei Reverse-Lookup-Tabellen.

Wir verwenden eine Tabelle, um die Bezeichnung nachzuschlagen, die wir für die Computertaste anzeigen möchten, die wir drücken, um eine Note zu spielen (deklariert als reverseLookupTextin Zeile 164 deklariert ), und eine zweite, um die tatsächlich gedrückte Taste nachzuschlagen (deklariert als reverseLookupin Zeile 165 deklariert ).

Der Kluge kann erkennen, dass beide Nachschlagetabellen Schlüsselcodes als Werte haben. Was ist also der Unterschied zwischen ihnen?

It turns out that (for reasons unknown to me) when you get a keycode that corresponds to a key and you try to use String.fromCharCode() method on that keycode, you don’t always get back the same string representing the pressed key.

For example, pressing left open bracket yields keycode 219 but when you actually try to convert the keycode back to a string using String.fromCharCode(219) it returns "Û". To get "[", you have to use key code 91. We replace the incorrect codes starting on line 168.

Getting the right keycode initially involved a bit of trial and error, but later I realized you can just use another function (getDispStr() on line 318) to force the correct string to be displayed.

The majority of the keys do behave properly but you can choose to start with a smaller keyboard so you don’t have to deal with incorrect keycodes.

3. Generate Keyboard

We start the keyboard generation process by selecting our element keyboard container with document.getElementById(‘keyboard’) on line 209.

On the next line, we declare the selectSound object and set the value property to zero to have audioSynth.js load the sound profile for piano. You may wish to enter a different value (can be 0-3) if you want to try out other instruments. See line 233 of audioSynth.js with Synth.loadSoundProfile for more details.

On line 216 with var notes, we retrieve the available notes for one octave (C, C#, D…B) from audioSynth.js.

We generate our keyboard by looping through each octave and then each note in that octave. For each note, we create a element to represent the appropriate key using document.createElement(‘div’).

To distinguish whether we need to create a black or white key, we look at the length of the note name. Adding a sharp sign makes the length of the string greater than one (ex. ‘C#’) which indicates a black key and vice versa for white.

For each key we can set a width, height, and an offset from the left based on key position. We can also set appropriate classes for use with CSS later.

Next, we label the key with the computer key we need to press to play its note and store it in another element. This is where reverseLookupText comes in handy. Inside the same , we also display the note name. We accomplish all of this by setting the label’s innerHTML property and appending the label to the key (lines 240-242).

label.innerHTML = '' + s + '' + '

' + n.substr(0,1) + '' + (__octave + parseInt(i)) + '' + (n.substr(1,1)?n.substr(1,1):'');

Similarly, we add an event listener to the key to handle mouse clicks (line 244):

thisKey.addEventListener(evtListener[0], (function(_temp) { return function() { fnPlayKeyboard({keyCode:_temp}); } })(reverseLookup[n + ',' + i]));

The first parameter evtListener[0] is a mousedown event declared much earlier on line 7. The second parameter is a function that returns a function. We need reverseLookup to get us the correct keycode and we pass that value as a parameter _temp to the inner function. We will not need reverseLookup to handle actual keydown events.

This code is pre-ES2015 (aka ES6) and the updated, hopefully clearer equivalent is:

const keyCode = reverseLookup[n + ',' + i]; thisKey.addEventListener('mousedown', () => { fnPlayKeyboard({ keyCode }); }); 

After creating and appending all necessary keys to our keyboard, we will need to handle the actual playing of a note.

4. Handle Key Presses

We handle key presses the same way whether the user clicks the key or presses the corresponding computer key through use of the function fnPlayKeyboard on line 260. The only difference is the type of event we use in addEventListener to detect the key press.

We set up an array called keysPressed in line 206 to detect what keys are being pressed/clicked. For simplicity, we will assume that a key being pressed can include it being clicked as well.

We can divide the process of handling key presses into 3 steps: adding the keycode of the pressed key to keysPressed, playing the appropriate note, and removing the keycode from keysPressed.

The first step of adding a keycode is easy:

keysPressed.push(e.keyCode);

where e is the event detected by addEventListener.

If the added keycode is one of the key bindings we assigned, then we call fnPlayNote() on line 304 to play the note associated with that key.

In fnPlayNote(), we first create a new Audio() element container for our note using the generate() method from audiosynth.js. When the audio loads, we can then play the note.

Lines 308-313 are legacy code and seem they can just be replaced by container.play(), though I have not done any extensive testing to see what the difference is.

Removing a key press is also quite straightforward, as you can just remove the key from the keysPressed array with the splice method on line 298. For more details, see the function called fnRemoveKeyBinding().

The only thing we have to watch out for is when the user holds down a key or multiple keys. We have to make sure that the note only plays once while a key is held down (lines 262-267):

var i = keysPressed.length; while(i--) { if(keysPressed[i]==e.keyCode) { return false; } } 

Returning false prevents the rest of fnPlayKeyboard() from executing.

Summary

We have created a fully functioning piano keyboard using vanilla JavaScript!

To recap, here are the steps we took:

  1. We set up our index HTML file to load the appropriate JS files and execute

    playKeyboard() in to generate and make the keyboard functional. We have a element with id= "keyboard" where the keyboard will be displayed on the page.

  2. In our JavaScript file playKeyboard.js, we set up our key bindings with keycodes as keys and musical notes as values. We also create two reverse lookup tables in which one is responsible for looking up the appropriate key label based on the note and the other for looking up the correct keycode.

  3. We dynamically generate the keyboard by looping through every note in each octave range. Each key is created as its own element. We use the reverse lookup tables to generate the key label and correct keycode. Then an event listener on mousedown uses it to call fnPlayKeyboard() to play the note. The

    keydown event calls the same function but does not need a reverse lookup table to get the keycode.

  4. We handle key presses resulting from either mouse clicks or computer key presses in 3 steps: add keycode of the pressed key to an array, play the appropriate note, and remove keycode from that array. We must be careful not to repeatedly play a note (from the beginning) while the user continuously holds down a key.

The keyboard is now fully functional but it may look a bit dull. I will leave the CSS part to you ?

Again, here is the JavaScript piano keyboard I made for reference.

If you want to learn more about web development and check out some other neat projects, visit my blog at 1000 Mile World.

Thanks for reading and happy coding!