Introducere în Web MIDI

"Un tutorial despre Web MIDI? În 2016? Glumești, nu?"

Nu! Nu este ceea ce crezi! Pentru cei dintre noi care am folosit Web-ul încă din anii '90, expresia "Web MIDI" induce flashback-uri la un moment dat când site-urile au jucat automat o versiune Lo-fi bloopy a Final Countdown în timp ce ai semnat cartea de oaspeți a webmasterului. Cu toate acestea, în 2016, Web MIDI - și mai ales MIDI API-ul Web - are un potențial mult mai mare.

Standardele MIDI pentru interfața digitală a instrumentelor muzicale. Este un protocol care permite instrumentelor muzicale electronice, computerelor și altor dispozitive să discute între ele. Funcționează prin trimiterea mesajelor mici de la dispozitiv la dispozitiv, spunând lucruri precum "nota 12 a fost doar apăsată" sau "nota 62 nu mai este presată", dar într-un stenogramă digitală.

API-ul MIDI Web utilizează acest protocol și vă permite să utilizați un instrument cu funcție MIDI, cum ar fi o tastatură, să îl conectați la computer și să aveți informații trimise de la tastatură în browser.

În prezent, aplicația Web MIDI API este acceptată numai în Chrome și Opera, dar puteți urmări progresul în Firefox accesând acest bug. 

Deci, de ce am dori să conectăm o tastatură la un browser web? Ei bine, nu mulți muzicieni cunosc modul în jurul valorii de o tastatură QWERTY la fel de mult ca ei fac un muzical. De asemenea, gama de dispozitive muzicale care acceptă MIDI este imensă. Prin conectarea unui dispozitiv de intrare activat cu MIDI la browserul nostru, împreună cu utilizarea API-ului Web Audio, putem crea instrumente muzicale pe web. 

Doriți să jucați un pian? Conectați doar tastatura și vizitați o pagină web care utilizează aceste tehnologii pentru a replica sunetul unui pian. Vrei un sunet diferit? Pur și simplu vizitați un site diferit.

Sperăm că puteți vedea beneficiul acestui API, dar cum funcționează de fapt?

Accesarea unui dispozitiv MIDI

Mai întâi dorim să verificăm dacă browserul nostru acceptă API-ul Web MIDI. Facem asta prin a vedea dacă navigator.requestMIDIAccess există. Această metodă este implementată numai în browserele care acceptă API-ul.

dacă (navigator.requestMIDIAccess) console.log ("Browserul acceptă MIDI!"); 

Acum că știm că metoda există, să o apelam ca să solicite acces la orice intrare MIDI care vine în browser.

dacă (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (succes, eșec); 

navigator.requestMIDIAccess () returneaza o promisiune, in sensul ca se va numi fie o functie de succes, fie o functie de esec in functie de rezultatul solicitarii accesului MIDI. Aici i-am dat numele celor două funcții pe care le vom crea în continuare.

succesul funcției (midi) console.log ('Am primit midi!', midi);  failure function () console.error ('Nu ai acces la dispozitivele midi.')

După cum puteți vedea, funcția noastră de succes are un parametru MIDI sub forma unui obiect MIDIAccess. Obiectul MIDIAccess este cheia pentru primirea datelor midi. Obiectul în sine oferă o interfață pentru orice dispozitive MIDI pe care le-ați atașat. Intrările reprezintă toate dispozitivele MIDI pe care le-ați conectat la computer. Am atașat o singură tastatură MIDI, așa că dacă mă înregistrez midi.inputs.size, ar produce "1".

Pentru a obține datele de intrare de pe dispozitivul nostru, mai întâi creați o variabilă și alocați-o midi.inputs.values ​​() ca astfel.

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

Un lucru important este de notat că valoarea atribuită intrări este un iterator. Un iterator este un obiect care știe cum să acceseze proprietățile sale unul câte unul, în timp ce ține evidența poziției curente din secvența de iterație. Acesta oferă o Următor →() pentru a vă permite să obțineți următorul element din secvență. De asemenea, are a Terminat proprietate pentru a ne spune dacă am iterat asupra tuturor proprietăților obiectului. Aceasta înseamnă că putem scrie fantezie pentru buclele de genul:

pentru (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // de fiecare dată când există un apel midi apel funcția onMIDIMessage input.value.onmidimessage = onMIDIMessage; 

Ceea ce se spune pentru buclă este:

  1. Creați o variabilă numită intrare și alocați următoarea intrare. Pentru că nu am repetat încă nicio intrare, aceasta va reveni la prima intrare.
  2. Dacă avem o intrare și valoarea de intrare a iteratorului de intrare nu este egală cu adevărat, continuați cu bucla.
  3. A stabilit intrare la următoarea intrare în obiectul nostru iterator.

Veți observa, de asemenea, că în interiorul acestui buclă atribuim o funcție funcției de intrare onmidimessage ascultător. Această funcție va fi apelată oricând un eveniment MIDI este recepționat de la dispozitivul reprezentat de intrarea respectivă. Să creăm această funcție:

funcția onMIDIMessage (mesaj) console.log (message.data); 

Decodarea datelor MIDI

Partea mesajului MIDI care ne interesează este datele sale; ce tip de eveniment MIDI a fost trimis? Ce tastă de pe tastatură a fost apăsată? 

Dacă urmăriți împreună cu acest tutorial, veți vedea că atunci când apăsați o tastă de pe tastatură, browserul va înregistra ceva de genul [144, 61, 95] la consola. Iar când iei degetul de pe tastă, browserul va înregistra din nou ceva ușor diferit [128, 61, 0].

Această matrice poate fi împărțită ca atare. Primul element este tipul de eveniment MIDI. Mesajele MIDI pot conține un număr destul de mic de evenimente și fiecare eveniment are un număr corespunzător. În cazul nostru, 144 hărți pentru a noteOn mesaj, indicând faptul că o tastă a fost apăsată, în timp ce 128 este a noteOff mesaj, spunându-ne că cheia nu mai este apăsată. Pentru o listă completă a posibilelor tipuri de evenimente MIDI, consultați lista de mesaje din caietul de sarcini MIDI.

A doua valoare din matrice reprezintă ce tastă de pe tastatură a fost apăsată. Fiecare notă de pe o tastatură are un număr de la 0 la 127. În exemplul de mai sus, am apăsat tasta 61, care, folosind acest tabel de căutare, văd un C #.

A treia și ultima valoare din matrice reprezintă viteza, în principiu viteza pe care a fost lovită cheia. Acest lucru poate fi folosit pentru a mimica redarea unui pian unde cheile pot fi redate încet sau pot fi lovite rapid și greu.

Acum, când știm ce număr cheie este apăsat sau eliberat, să-l transformăm în ceva util. Să conectăm API-ul Web MIDI la API-ul Web Audio. Dacă nu sunteți familiarizat cu API-ul Web Audio, consultați seria de tutoriale pe acel subiect.

Crearea unui instrument Web

Să transformăm browserul nostru într-un mini sintetizator. Vom dori să creăm un oscilator care generează frecvența notei presate, așa că va trebui să convertim numărul notei MIDI la frecvența sa relevantă. Din fericire, bunul nostru prieten Wikipedia ne dă un mic algoritm pentru a face acest lucru. Iată cum arată în forma JavaScript:

funcția midiNoteToFrequency (notă) return Math.pow (2, (notă - 69) / 12)) * 440; 

Dați-i o notă și scoateți frecvența înapoi. Să folosim asta în nostru onMIDIMessage funcţie.

funcția onMIDIMessage (mesaj) var frequency = midiNoteToFrequency (message.data [1]); 

Apoi, dorim să redați o notă de această frecvență dacă mesajul MIDI este a noteOn mesaj.

dacă (message.data [0] === 144 && message.data [2]> 0) playNote (frecvență); 

Veți înțelege probabil prima parte a acestui lucru dacă declarație destul de ușor. Verificăm că tipul de mesaj este 144 care este noteOn mesaj.

Dar partea a doua? Ei bine, unele dispozitive MIDI, în loc de a trimite o noteOff mesaj, va trimite un mesaj noteOn mesaj cu viteza zero, așa că verificăm mesajul are o viteză mai mare decât zero. 

Acum ce am făcut noteOn acoperit, vom scrie ceva similar pentru noteOffNoteOffvaloarea mesajului este de 128, deci trebuie să verificăm nu numai acea valoare, dar și dacă viteza sa era zero pentru a acoperi situația pe care tocmai am menționat-o.

dacă (message.data [0] === 128 || message.data [2] === 0) stopNote (frecvență); 

Tot ce trebuie să facem acum este să completați startNote și stopNote funcții. Aceasta este misiunea aplicației Web Audio API și, prin urmare, este din păcate în afara scopului acestui tutorial, dar dacă cunoașteți API, atunci codul complet de mai jos ar trebui să fie destul de explicabil. 

Dacă nu, verificați seria mea pe API Web Audio, care include cum să construiți un sintetizator. Codul din acest tutorial este similar cu ceea ce am făcut aici, așadar ar fi locul perfect pentru a aplica ceea ce ați învățat aici.

var context = nou AudioContext (), oscilatoare = ; dacă (navigator.requestMIDIAccess) navigator.requestMIDIAccess () .then (succes, eșec);  funcția de succes (midi) var inputs = midi.inputs.values ​​(); // intrare este un Iterator pentru (var input = inputs.next (); input &&! input.done; input = inputs.next ()) // de fiecare dată când există un mesaj midi apelați funcția onMIDIMessage input.value. onmidimessage = onMIDIMessage;  funcția eșec () console.error ("Nu există acces la dispozitivele dvs. midi.") funcția onMIDIMessage (mesaj) var frequency = midiNoteToFrequency (message.data [1]); dacă (message.data [0] === 144 && message.data [2]> 0) playNote (frecvență);  dacă (message.data [0] === 128 || message.data [2] === 0) stopNote (frecvență);  funcția midiNoteToFrequency (notă) return Math.pow (2, ((notă - 69) / 12)) * 440;  funcția playNote (frecvență) oscilatoare [frecvență] = context.createOscillator (); oscilatoare [frecvență] .frequency.value = frecvență; oscilatoare [frecvență] .Cuplarea (context.destination); oscilatoare [frecvență] .start (context.currentTime);  funcția stopNot (frecvență) oscilatori [frecvență] .stop (context.currentTime); oscilatoare [frecvență] .disconnect (); 

Ce urmează?

Tine minte, noteOn și noteOff sunt doar două dintre tipurile de mesaje disponibile pentru noi, iar o tastatură MIDI este doar unul dintre cele mai multe tipuri de dispozitive MIDI. Nici măcar nu trebuie să folosiți MIDI pentru a face ceva muzical. Un joc HTML5 pe care îl jucați folosind o trompetă MIDI? Sună ca și chestia mea.

Cod