"Een tutorial over Web MIDI? In 2016? Je maakt een grapje, toch?"
Nee! Het is niet wat je denkt! Voor degenen onder ons die sinds de jaren negentig het web hebben gebruikt, induceert de uitdrukking 'Web MIDI' meestal flashbacks naar een tijd waarin websites automatisch een lo-fi bloopy-versie van The Final Countdown speelden terwijl je het gastenboek van de webmaster tekende. In 2016 heeft Web MIDI - en met name de Web MIDI API - veel meer mogelijkheden.
MIDI-standaarden voor digitale interface van muziekinstrumenten. Het is een protocol waarmee elektronische muziekinstrumenten, computers en andere apparaten met elkaar kunnen praten. Het werkt door het verzenden van kleine berichten van apparaat naar apparaat en zegt dingen als "noot 12 is net ingedrukt" of "noot 62 wordt niet meer ingedrukt", maar in een digitale steno.
De Web MIDI API gebruikt dit protocol en biedt u de mogelijkheid om een MIDI-geschikt instrument zoals een toetsenbord te gebruiken, het op uw computer aan te sluiten en informatie te laten verzenden van het toetsenbord naar uw browser.
Momenteel wordt de Web MIDI API alleen ondersteund in Chrome en Opera, maar u kunt de voortgang in Firefox volgen door deze bug te bezoeken.
Dus waarom zouden we een toetsenbord met een webbrowser willen verbinden? Nou, niet veel muzikanten weten net zo goed hun weg op een QWERTY-toetsenbord te vinden als een muzikaal toetsenbord. Ook is het bereik van muzikale apparaten die MIDI ondersteunen enorm. Door een MIDI-ingeschakelde invoerapparaat aan te sluiten op onze browser, samen met de Web Audio API, kunnen we muziekinstrumenten maken op het web.
Wil je een piano spelen? Verbind gewoon uw toetsenbord en bezoek een webpagina die deze technologieën gebruikt om het geluid van een piano te reproduceren. Wil je een ander geluid? Bezoek eenvoudig een andere site.
Hopelijk ziet u het voordeel van deze API, maar hoe werkt deze eigenlijk??
Eerst willen we controleren of onze browser de Web MIDI API ondersteunt. We doen dit door te kijken of het navigator.requestMIDIAccess
methode bestaat. Deze methode is alleen geïmplementeerd in browsers die de API ondersteunen.
if (navigator.requestMIDIAccess) console.log ('Browser ondersteunt MIDI!');
Nu we weten dat de methode bestaat, laten we het noemen om toegang te vragen tot elke MIDI-invoer die de weg van de browser is.
if (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (succes, mislukking);
navigator.requestMIDIAccess ()
retourneert een belofte, wat betekent dat het een succesfunctie of een faalfunctie zal oproepen, afhankelijk van de uitkomst van het verzoek om MIDI-toegang. Hier hebben we het de namen gegeven van twee functies die we nu gaan creëren.
functiesucces (midi) console.log ('Got midi!', midi); function failure () console.error ('Geen toegang tot uw midi-apparaten.')
Zoals u kunt zien, neemt onze succesfunctie een MIDI-parameter in de vorm van een MIDIAccess-object. Het MIDIAccess-object is de sleutel tot het ontvangen van midi-gegevens. Het object zelf biedt een interface voor alle MIDI-apparaten die u hebt aangesloten. Ingangen vertegenwoordigen alle MIDI-apparaten die u op uw computer hebt aangesloten. Ik heb een enkel MIDI-toetsenbord aangesloten, dus als ik zou inloggen midi.inputs.size
, het zou "1" uitvoeren.
Om de invoergegevens van ons apparaat te krijgen, maken we eerst een variabele en wijzen deze toe midi.inputs.values ()
zoals zo.
var inputs = midi.inputs.values ();
Een belangrijk ding om op te merken is dat de waarde toegewezen aan input
is een iterator. Een iterator is een object dat de eigenschappen ervan één voor één weet te benaderen, terwijl de huidige positie in de iteratiesequentie wordt bijgehouden. Het biedt een next ()
methode om het volgende item in de reeks te krijgen. Het heeft ook een gedaan
eigenschap om ons te laten weten of we over alle eigenschappen van het object hebben geïtereerd. Dit betekent dat we fancy kunnen schrijven voor loops als deze:
for (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // elke keer dat er een midi-bericht is, roept u de functie onMIDIMessage op input.value.onmidimessage = onMIDIMessage;
Wat dit voor lus zegt, is:
invoer
en wijs de volgende invoer eraan toe. Omdat we nog geen iteratie hebben gehad over de invoer, zal dit de eerste van onze invoer opleveren.invoer
naar de volgende invoer in ons iterator-object.Je zult ook merken dat we binnen deze lus een functie toewijzen aan de invoer onmidimessage
luisteraar. Deze functie wordt elke keer dat een MIDI-gebeurtenis wordt ontvangen van het apparaat dat door die ingang wordt weergegeven, opgeroepen. Laten we die functie creëren:
function onMIDIMessage (bericht) console.log (message.data);
Het deel van het MIDI-bericht waarin we geïnteresseerd zijn, zijn de gegevens; welk type MIDI-evenement werd verzonden? Op welke toets van het toetsenbord werd gedrukt?
Als u deze zelfstudie volgt, ziet u dat wanneer u op een toets op uw toetsenbord drukt, de browser zich als volgt zal aanmelden [144, 61, 95]
naar de console. En wanneer u uw vinger van de toets haalt, zal de browser opnieuw iets anders registreren, zoals [128, 61, 0]
.
Deze array kan op dezelfde manier worden opgesplitst. Het eerste element is het type MIDI-gebeurtenis. MIDI-berichten kunnen een vrij klein aantal gebeurtenissen bevatten en elke gebeurtenis heeft een overeenkomstig nummer. In ons geval zijn 144 kaarten toegewezen aan a noteOn
bericht dat aangeeft dat een toets is ingedrukt, terwijl 128 een is noteOff
bericht dat de sleutel niet meer wordt ingedrukt. Zie de berichtenlijst in de MIDI-specificatie voor een volledige lijst met mogelijke MIDI-gebeurtenistypen.
De tweede waarde in de array geeft aan welke toets op het toetsenbord is ingedrukt. Elke noot op een toetsenbord krijgt een nummer van 0 tot 127. In het bovenstaande voorbeeld heb ik op toets 61 gedrukt, die met behulp van deze opzoektabel die we kunnen zien een C # was.
De derde en laatste waarde in de array geeft de snelheid weer, in feite de snelheid waarmee de toets werd geraakt. Dit kan worden gebruikt om het spelen van een piano na te bootsen, waarbij de toetsen zacht kunnen worden bespeeld of snel en hard kunnen worden geslagen.
Nu we weten welk nummer wordt ingedrukt of vrijgegeven, laten we het in iets nuttigs veranderen. Laten we de Web MIDI API aansluiten op de Web Audio API. Als u niet vertrouwd bent met de Web Audio API, bekijk dan mijn serie tutorials over datzelfde onderwerp.
Laten we van onze browser een mini-synthesizer maken. We willen een oscillator maken die de frequentie van de gespeelde noot genereert, dus we moeten het MIDI-nootnummer converteren naar de relevante frequentie. Gelukkig geeft onze goede vriend Wikipedia ons een klein algoritme om dit te doen. Hier is hoe het eruit ziet in JavaScript-vorm:
functie midiNoteToFrequency (opmerking) return Math.pow (2, ((note - 69) / 12)) * 440;
Geef het een notitie en krijg de frequentie terug. Laten we dit gebruiken in onze onMIDIMessage
functie.
function onMIDIMessage (bericht) var frequency = midiNoteToFrequency (message.data [1]);
Vervolgens willen we een noot van deze frequentie spelen als het MIDI-bericht een is noteOn
bericht.
if (message.data [0] === 144 && message.data [2]> 0) playNote (frequentie);
Je zult waarschijnlijk het eerste deel hiervan begrijpen als
verklaring vrij gemakkelijk. We controleren dat het berichttype 144 is, dat is de noteOn
bericht.
Maar hoe zit het met het tweede deel? Wel, sommige MIDI-apparaten, in plaats van een noteOff
bericht, stuurt een noteOn
bericht met nulsnelheid, dus we controleren of het bericht een snelheid heeft die groter is dan nul.
Nu dat we hebben noteOn
gedekt, we zullen iets soortgelijks voor schrijven noteOff
. NoteOff
De waarde van het bericht is 128, dus we moeten niet alleen voor die waarde controleren, maar ook of de snelheid nul was om de situatie te dekken die ik net noemde.
if (message.data [0] === 128 || message.data [2] === 0) stopNote (frequentie);
Het enige wat we nu moeten doen, is het invullen van de startNote
en stopNote
functies. Dit is de taak van de Web Audio API en valt daarom helaas buiten het bestek van deze zelfstudie, maar als u de API kent, moet de onderstaande volledige code voor zichzelf spreken..
Als dat niet het geval is, bekijk dan mijn serie over de Web Audio API, die inhoudt hoe een synthesizer moet worden gemaakt. De code in die tutorial is vergelijkbaar met wat ik hier heb gedaan, dus zou de perfecte plek zijn om toe te passen wat je hier hebt geleerd.
var context = new AudioContext (), oscillators = ; if (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (succes, mislukking); function success (midi) var inputs = midi.inputs.values (); // inputs is een Iterator voor (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // elke keer dat er een midi-bericht is, roept u de functie onMIDIMessage input.value aan. onmidimessage = onMIDIMessage; function failure () console.error ('Geen toegang tot uw midi-apparaten.') function onMIDIMessage (bericht) var frequency = midiNoteToFrequency (message.data [1]); if (message.data [0] === 144 && message.data [2]> 0) playNote (frequentie); if (message.data [0] === 128 || message.data [2] === 0) stopNote (frequentie); functie midiNoteToFrequency (opmerking) return Math.pow (2, ((note - 69) / 12)) * 440; function playNote (frequentie) oscillators [frequentie] = context.createOscillator (); oscillatoren [frequentie] .frequency.value = frequentie; oscillatoren [frequentie] .Op (context.destination); oscillatoren [frequentie] .start (context.currentTime); function stopNote (frequentie) oscillators [frequentie] .stop (context.currentTime); oscillatoren [frequentie] .Trek ();
Onthouden, noteOn
en noteOff
zijn slechts twee van de berichttypen die voor ons beschikbaar zijn, en een MIDI-toetsenbord is slechts een van de vele, vele soorten MIDI-apparaten. Je hoeft zelfs geen MIDI te gebruiken om iets muzikaals te maken. Een HTML5-game die je speelt met een MIDI-trompet? Klinkt als gewoon mijn ding.