Introduksjon til Web MIDI

"En veiledning om Web MIDI? I 2016? Du tuller, sant?"

Nei! Det er ikke det du tror! For de av oss som har brukt nettet siden 1990-tallet, uttrykker "Web MIDI" vanligvis flashbacks til en tid da nettsteder automatisk spilte en lo-fi bloopy versjon av The Final Countdown mens du signerte webmasterens gjestebok. Imidlertid, i 2016, har Web MIDI-og spesielt Web MIDI API-en mye mer potensial.

MIDI standarder for Musical Instrument Digital Interface. Det er en protokoll som tillater elektroniske musikkinstrumenter, datamaskiner og andre enheter å snakke med hverandre. Det virker ved å sende små meldinger fra enhet til enhet som sier ting som "notat 12 var bare trykket" eller "notat 62 ikke blir presset lenger", men i en digital stenografi.

Web MIDI API bruker denne protokollen og lar deg ta et MIDI-aktivert instrument, for eksempel et tastatur, koble det til datamaskinen din og ha informasjon sendt fra tastaturet til nettleseren din.

For øyeblikket støttes Web MIDI API bare i Chrome og Opera, men du kan følge utviklingen i Firefox ved å besøke denne feilen. 

Så hvorfor vil vi koble et tastatur til en nettleser? Vel, ikke mange musikere kjenner seg rundt et QWERTY-tastatur så mye som de gjør en musikalsk. Også, spekteret av musikalske enheter som støtter MIDI er stort. Ved å koble en MIDI-aktivert inngangsenhet til nettleseren vår, sammen med å bruke Web Audio API, kan vi lage musikkinstrumenter på nettet. 

Vil du spille et piano? Bare koble tastaturet ditt og besøk en nettside som bruker disse teknologiene til å kopiere lyden av et piano. Vil du ha en annen lyd? Bare besøk et annet nettsted.

Forhåpentligvis kan du se nytte av denne APIen, men hvordan fungerer det egentlig?

Tilgang til en MIDI-enhet

Først vil vi sjekke om nettleseren vår støtter Web MIDI API. Vi gjør dette ved å se om navigator.requestMIDIAccess metode finnes. Denne metoden implementeres bare i nettlesere som støtter API-en.

hvis (navigator.requestMIDIAccess) console.log ('Nettleser støtter MIDI!'); 

Nå som vi vet at metoden eksisterer, la oss kalle det for å be om tilgang til hvilken som helst MIDI-inngang som kommer i nettleserens måte.

hvis (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (suksess, feil); 

navigator.requestMIDIAccess () returnerer et løfte, noe som betyr at det enten vil kalle en suksessfunksjon eller en feilfunksjon, avhengig av utfallet av det som ber om MIDI-tilgang. Her har vi gitt navnet på to funksjoner vi skal lage neste.

funksjon suksess (midi) console.log ('Got midi!', midi);  funksjonsfeil () console.error ('Ingen tilgang til midi-enhetene dine.')

Som du kan se, tar vår suksessfunksjon en MIDI-parameter i form av et MIDIAccess-objekt. MIDIAccess-objektet er nøkkelen til mottak av MIDI-data. Objektet selv gir et grensesnitt til alle MIDI-enheter du har vedlagt. Inngang representerer MIDI-enheter du har koblet til datamaskinen din. Jeg har et enkelt MIDI-tastatur festet, så hvis jeg skulle logge midi.inputs.size, det ville utdata "1".

For å få inndataene fra enheten, oppretter vi først en variabel og tilordner den midi.inputs.values ​​() som så.

var inputs = midi.inputs.values ​​();

En viktig ting å merke seg er at verdien tilordnet innganger er en iterator. En iterator er et objekt som vet hvordan man får tilgang til egenskapene en om gangen, samtidig som man holder øye med den nåværende posisjonen i iterasjonssekvensen. Det gir en neste () metode for å tillate deg å få neste objekt i sekvensen. Den har også a ferdig eiendom for å gi oss beskjed hvis vi har iterated over alle egenskapene til objektet. Dette betyr at vi kan skrive fancy for løkker som dette:

for (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // hver gang det er en midi-melding, ring funksjonen onMIDIMessage input.value.onmidimessage = onMIDIMessage; 

Hva dette for sløyfe sier er:

  1. Opprett en variabel som heter inngang og tilordne neste inngang til den. Fordi vi ikke har iterated over noen innganger ennå, vil dette returnere den første av våre innganger.
  2. Hvis vi har en inngang og inngangslyserens ferdige verdi ikke er lik sant, så fortsett med sløyfen.
  3. Sett inngang til neste inngang i vårt iteratorobjekt.

Du vil også merke seg at inne i denne for løkken gir vi en funksjon til inngangens onmidimessage lytteren. Denne funksjonen vil bli kalt når som helst en MIDI-hendelse er mottatt fra enheten som er representert av denne inngangen. La oss skape den funksjonen:

funksjon onMIDIMessage (melding) console.log (message.data); 

Dekoding av MIDI-data

Den delen av MIDI meldingen vi er interessert i er dens data; hvilken type MIDI-hendelse ble sendt? Hvilken tast på tastaturet ble trykket? 

Hvis du følger med denne opplæringen, vil du se at når du trykker på en tast på tastaturet, logger nettleseren noe som [144, 61, 95] til konsollen. Og når du tar fingeren av nøkkelen, vil nettleseren logge på noe litt annerledes, for eksempel [128, 61, 0].

Dette arrayet kan brytes ned som det. Det første elementet er typen MIDI-hendelse. MIDI-meldinger kan inneholde et ganske lite antall hendelser, og hver hendelse har et tilsvarende nummer. I vårt tilfelle, 144 kart til en noteOn melding, som indikerer at en tast er trykket, mens 128 er a noteOff melding, forteller oss at nøkkelen ikke lenger er trykket. For en fullstendig liste over mulige MIDI-hendelsestyper, sjekk ut meldingslisten i MIDI-spesifikasjonen.

Den andre verdien i matrisen representerer hvilken tast på tastaturet som ble trykket. Hver notat på tastaturet er gitt et tall fra 0 til 127. I eksemplet ovenfor presset jeg tast 61, som ved å bruke denne oppslagstabellen vi kan se, var en C #.

Den tredje og endelige verdien i gruppen representerer hastighet, i utgangspunktet hastigheten som nøkkelen ble rammet. Dette kan brukes til å etterligne å spille et piano hvor nøkler kan spilles mykt eller rammes raskt og hardt.

Nå som vi vet hvilket nøkkelnummer som blir presset eller utgitt, la oss gjøre det til noe nyttig. La oss koble Web MIDI API til Web Audio API. Hvis du ikke er kjent med Web Audio API, sjekk ut min serie av opplæringsprogrammer på det aktuelle emnet.

Opprette et webinstrument

La oss omdanne vår nettleser til en mini-synthesizer. Vi vil lage en oscillator som genererer frekvensen av notatet, så vi må konvertere MIDI notatnummeret til den aktuelle frekvensen. Heldigvis gir vår gode venn Wikipedia oss en liten algoritme for å gjøre nettopp dette. Slik ser det ut i JavaScript-skjema:

funksjon midiNoteToFrequency (notat) return Math.pow (2, ((note - 69) / 12)) * 440; 

Gi det et notat og få frekvensen tilbake. La oss bruke dette i vår onMIDIMessage funksjon.

funksjon onMIDIMessage (melding) var frequency = midiNoteToFrequency (message.data [1]); 

Deretter ønsker vi å spille et notat av denne frekvensen hvis MIDI-meldingen er en noteOn budskap.

hvis (message.data [0] === 144 && message.data [2]> 0) playNote (frekvens); 

Du forstår trolig den første delen av dette hvis uttalelse ganske enkelt. Vi kontrollerer at meldingstypen er 144 som er den noteOn budskap.

Men hva med den andre delen? Vel, noen MIDI-enheter, i stedet for å sende en noteOff melding, vil sende en noteOn melding med null hastighet, så vi sjekker meldingen har en hastighet som er større enn null. 

Nå som vi har noteOn dekket, vi skal skrive noe lignende for noteOffNoteOffs meldingsverdi er 128, så vi må sjekke ikke bare for den verdien, men også om hastigheten var null for å dekke situasjonen jeg nettopp nevnte.

hvis (message.data [0] === 128 || message.data [2] === 0) stopNote (frekvens); 

Alt vi trenger å gjøre nå er å fylle ut startNote og stopNote funksjoner. Dette er jobben til Web Audio API, og er derfor dessverre utenfor omfanget av denne opplæringen, men hvis du kjenner API-en, så må hele koden nedenfor være ganske selvforklarende. 

Hvis ikke, sjekk ut serien min på Web Audio API, som inkluderer hvordan du bygger en synthesizer. Koden i den opplæringen ligner på det jeg har gjort her, så det ville være det perfekte stedet å bruke det du har lært her.

var context = new AudioContext (), oscillators = ; hvis (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (suksess, feil);  funksjon suksess (midi) var inputs = midi.inputs.values ​​(); // inputs er en Iterator for (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // hver gang det er en midi-melding ringe onMIDIMessage-funksjonen input.value. onmidimessage = onMIDIMessage;  funksjonsfeil () console.error ('Ingen tilgang til midi-enhetene dine.') funksjon onMIDIMessage (melding) var frequency = midiNoteToFrequency (message.data [1]); hvis (message.data [0] === 144 && message.data [2]> 0) playNote (frekvens);  hvis (message.data [0] === 128 || message.data [2] === 0) stopNote (frekvens);  funksjon midiNoteToFrequency (notat) return Math.pow (2, ((note - 69) / 12)) * 440;  funksjon playNote (frekvens) oscillators [frequency] = context.createOscillator (); oscillatorer [frekvens] .frequency.value = frekvens; oscillatorer [frekvens] .Tilkoble (context.destination); oscillatorer [frekvens] .start (context.currentTime);  funksjon stopNote (frekvens) oscillators [frequency] .stop (context.currentTime); oscillatorer [frekvens] .disconnect (); 

Hva nå?

Huske, noteOn og noteOff er bare to av meldingstypene tilgjengelige for oss, og et MIDI-tastatur er bare en av de mange, mange typer MIDI-enheter. Du trenger ikke engang å bruke MIDI til å lage noe musikalsk. Et HTML5-spill du spiller med en MIDI-trompet? Høres ut som bare min ting.