Web MIDI简介
“有關(guān)Web MIDI的教程? 在2016年? 你開(kāi)玩笑的對(duì)吧?”
沒(méi)有! 這不是你的想法! 對(duì)于我們自1990年代以來(lái)一直使用網(wǎng)絡(luò)的用戶來(lái)說(shuō),“ Web MIDI”一詞通常會(huì)引起倒敘,直到網(wǎng)站上您在簽署網(wǎng)站管理員的留言簿時(shí)自動(dòng)播放低俗版的《最終倒計(jì)時(shí)》。 但是,在2016年,Web MIDI(尤其是Web MIDI API)具有更大的潛力。
樂(lè)器數(shù)字接口的MIDI標(biāo)準(zhǔn)。 該協(xié)議允許電子樂(lè)器,計(jì)算機(jī)和其他設(shè)備相互通信。 它通過(guò)從一臺(tái)設(shè)備向另一臺(tái)設(shè)備發(fā)送小消息來(lái)工作,例如說(shuō)“剛剛按下了注釋12”或“不再按下注釋62”,但是是以數(shù)字的形式表示的。
Web MIDI API使用此協(xié)議,并允許您使用支持MIDI的樂(lè)器(例如鍵盤(pán)),將其連接到計(jì)算機(jī),并將信息從鍵盤(pán)發(fā)送到瀏覽器。
目前, Chrome和Opera中僅支持 Web MIDI API,但是您可以通過(guò)訪問(wèn)此Bug來(lái)跟蹤其在Firefox中的進(jìn)度。
那么,為什么我們要將鍵盤(pán)連接到Web瀏覽器呢? 好吧,沒(méi)有多少音樂(lè)家像音樂(lè)演奏家那樣了解QWERTY鍵盤(pán)。 另外,支持MIDI的音樂(lè)設(shè)備種類繁多。 通過(guò)將支持MIDI的輸入設(shè)備連接到我們的瀏覽器,以及使用Web Audio API,我們可以在網(wǎng)絡(luò)上創(chuàng)建樂(lè)器。
想彈鋼琴嗎? 只需連接鍵盤(pán),然后訪問(wèn)使用這些技術(shù)復(fù)制鋼琴聲音的網(wǎng)頁(yè)即可。 想要不同的聲音? 只需訪問(wèn)其他站點(diǎn)。
希望您可以看到此API的好處,但是它實(shí)際上如何工作?
訪問(wèn)MIDI設(shè)備
首先,我們要檢查我們的瀏覽器是否支持Web MIDI API。 我們通過(guò)查看是否存在navigator.requestMIDIAccess方法來(lái)完成此操作。 僅在支持API的瀏覽器中實(shí)現(xiàn)此方法。
if (navigator.requestMIDIAccess) {console.log('Browser supports MIDI!'); }現(xiàn)在我們知道該方法存在,讓我們調(diào)用它以請(qǐng)求訪問(wèn)瀏覽器附帶的任何MIDI輸入。
if (navigator.requestMIDIAccess) {navigator.requestMIDIAccess().then(success, failure); }navigator.requestMIDIAccess()返回一個(gè)promise,這意味著它將根據(jù)請(qǐng)求MIDI訪問(wèn)的結(jié)果調(diào)用成功函數(shù)或失敗函數(shù)。 在這里,我們給了它接下來(lái)要?jiǎng)?chuàng)建的兩個(gè)函數(shù)的名稱。
function success (midi) {console.log('Got midi!', midi); }function failure () {console.error('No access to your midi devices.') }如您所見(jiàn),我們的成功函數(shù)采用MIDIAc??cess對(duì)象形式的MIDI參數(shù)。 MIDIAc??cess對(duì)象是接收Midi數(shù)據(jù)的關(guān)鍵。 對(duì)象本身為您連接的任何MIDI設(shè)備提供了接口。 輸入代表您已連接到計(jì)算機(jī)的任何MIDI設(shè)備。 我連接了一個(gè)MIDI鍵盤(pán),因此,如果要登錄midi.inputs.size ,它將輸出“ 1”。
為了從我們的設(shè)備獲取輸入數(shù)據(jù),我們首先創(chuàng)建一個(gè)變量,然后像這樣給它分配midi.inputs.values() 。
var inputs = midi.inputs.values();需要注意的重要一點(diǎn)是,分配給inputs的值是一個(gè)迭代器 。 迭代器是一個(gè)對(duì)象,它知道如何一次訪問(wèn)其屬性,同時(shí)跟蹤迭代序列中的當(dāng)前位置。 它提供了next()方法,使您可以獲取序列中的下一項(xiàng)。 它也有一個(gè)done屬性,讓我們知道是否已遍歷對(duì)象的所有屬性。 這意味著我們可以為這樣的循環(huán)編寫(xiě)奇特的代碼:
for (var input = inputs.next();input && !input.done;input = inputs.next()) {// each time there is a midi message call the onMIDIMessage functioninput.value.onmidimessage = onMIDIMessage; } 這個(gè)for循環(huán)的意思是:
您還將注意到,在此for循環(huán)內(nèi),我們?yōu)檩斎氲膐nmidimessage偵聽(tīng)器分配了一個(gè)函數(shù)。 每當(dāng)從該輸入所代表的設(shè)備接收到MIDI事件時(shí),都會(huì)調(diào)用此函數(shù)。 讓我們創(chuàng)建一個(gè)函數(shù):
function onMIDIMessage (message) {console.log(message.data); }解碼MIDI數(shù)據(jù)
我們感興趣的MIDI消息部分是數(shù)據(jù)。 發(fā)送了什么類型的MIDI事件? 按下鍵盤(pán)上的哪個(gè)鍵?
如果按照本教程進(jìn)行操作,將會(huì)看到,當(dāng)您按下鍵盤(pán)上的某個(gè)鍵時(shí),瀏覽器會(huì)將類似[144, 61, 95]到控制臺(tái)。 當(dāng)您將手指移開(kāi)按鍵時(shí),瀏覽器將再次記錄稍微不同的內(nèi)容,例如[128, 61, 0] 。
這樣的數(shù)組可以分解。 第一個(gè)元素是MIDI事件的類型。 MIDI消息可以包含相當(dāng)少量的事件,并且每個(gè)事件都有一個(gè)相應(yīng)的數(shù)目。 在我們的示例中,144映射到noteOn消息,表示已按下某個(gè)鍵,而128則是noteOff消息,告訴我們不再按下該鍵。 有關(guān)可能的MIDI事件類型的完整列表,請(qǐng)查看MIDI規(guī)范中的消息列表。
數(shù)組中的第二個(gè)值表示按下了鍵盤(pán)上的哪個(gè)鍵。 鍵盤(pán)上的每個(gè)音符都有一個(gè)從0到127的數(shù)字。在上面的示例中,我按下了鍵61,通過(guò)使用此查找表,我們可以看到它是C#。
數(shù)組中的第三個(gè)也是最后一個(gè)值表示速度,基本上是按鍵的速度。 這可以用來(lái)模擬彈奏鋼琴時(shí)的琴鍵,既可以輕柔地彈奏琴鍵,也可以快速而硬地敲擊琴鍵。
現(xiàn)在我們知道正在按下或釋放哪個(gè)鍵號(hào),讓我們將其變成有用的東西。 讓我們將Web MIDI API與Web Audio API掛鉤。 如果您不熟悉Web Audio API,請(qǐng)查看我有關(guān)該主題的系列教程 。
創(chuàng)建網(wǎng)絡(luò)工具
讓我們將瀏覽器變成一個(gè)小型合成器。 我們將要?jiǎng)?chuàng)建一個(gè)振蕩器,該振蕩器生成所按下音符的頻率,因此我們需要將MIDI音符編號(hào)轉(zhuǎn)換為其相關(guān)頻率。 幸運(yùn)的是,我們的好朋友Wikipedia為我們提供了一些算法來(lái)做到這一點(diǎn)。 這是JavaScript形式的樣子:
function midiNoteToFrequency (note) {return Math.pow(2, ((note - 69) / 12)) * 440; }給它一個(gè)音符,然后返回頻率。 讓我們?cè)趏nMIDIMessage函數(shù)中使用它。
function onMIDIMessage (message) {var frequency = midiNoteToFrequency(message.data[1]); }接下來(lái),如果MIDI消息是noteOn消息,則我們要播放此頻率的音符。
if (message.data[0] === 144 && message.data[2] > 0) {playNote(frequency); }您可能會(huì)很容易理解if語(yǔ)句的第一部分。 我們正在檢查消息類型為144,即noteOn消息。
但是第二部分呢? 好吧,某些MIDI設(shè)備將發(fā)送零速度的noteOn消息,而不是發(fā)送noteOff消息,因此我們正在檢查消息的速度是否大于零。
現(xiàn)在我們已經(jīng)覆蓋了noteOn ,我們將為noteOff編寫(xiě)類似的noteOff 。 NoteOff的消息值是128,因此我們不僅需要檢查該值,還要檢查它的速度是否為零,以覆蓋我剛才提到的情況。
if (message.data[0] === 128 || message.data[2] === 0) {stopNote(frequency); }我們現(xiàn)在要做的就是填寫(xiě)startNote和stopNote函數(shù)。 這是Web Audio API的工作,因此可悲地超出了本教程的范圍,但是如果您知道該API,則下面的完整代碼應(yīng)該是不言而喻的。
如果沒(méi)有,請(qǐng)查看有關(guān)Web Audio API的系列文章 ,其中包括如何構(gòu)建合成器 。 該教程中的代碼與我在這里所做的相似,因此將是應(yīng)用您在這里學(xué)到的知識(shí)的理想之地。
var context = new AudioContext(),oscillators = {};if (navigator.requestMIDIAccess) {navigator.requestMIDIAccess().then(success, failure); }function success (midi) {var inputs = midi.inputs.values();// inputs is an Iteratorfor (var input = inputs.next(); input && !input.done; input = inputs.next()) {// each time there is a midi message call the onMIDIMessage functioninput.value.onmidimessage = onMIDIMessage;} }function failure () {console.error('No access to your midi devices.') }function onMIDIMessage (message) {var frequency = midiNoteToFrequency(message.data[1]);if (message.data[0] === 144 && message.data[2] > 0) {playNote(frequency);}if (message.data[0] === 128 || message.data[2] === 0) {stopNote(frequency);} }function midiNoteToFrequency (note) {return Math.pow(2, ((note - 69) / 12)) * 440; }function playNote (frequency) {oscillators[frequency] = context.createOscillator();oscillators[frequency].frequency.value = frequency;oscillators[frequency].connect(context.destination);oscillators[frequency].start(context.currentTime); }function stopNote (frequency) {oscillators[frequency].stop(context.currentTime);oscillators[frequency].disconnect(); }接下來(lái)是什么?
請(qǐng)記住, noteOn和noteOff只是我們可用的兩種消息類型,而MIDI鍵盤(pán)只是許多類型的MIDI設(shè)備之一。 您甚至不必使用MIDI來(lái)制作音樂(lè)作品。 您使用MIDI小號(hào)玩HTML5游戲嗎? 聽(tīng)起來(lái)就像我的事。
翻譯自: https://code.tutsplus.com/tutorials/introduction-to-web-midi--cms-25220
總結(jié)
以上是生活随笔為你收集整理的Web MIDI简介的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: SDN开源,从你的全世界路过
- 下一篇: Java实现:LeetCode活字印刷