p5.js 、 Tone.js、手機三軸感測器實作教學 —— 單手拍手機?!

不管到哪都拿著手機,已經是非常稀鬆平常的當代景象了。

看看公車站、捷運站、餐廳、美術館的人們手上,而手機從可以輕鬆握在掌心的大小,進化到現在螢幕還在持續變大中,因此,人們常常是一手拿著手機,一隻手空著以應付各種突發事件。

但是,一隻手總被佔據的時候,總是會遇到一些尷尬的處境。吃飯、上廁所倒還行,但萬一當你在拿手機的時候,突然遇到了必須用雙手的場合呢?

像是拍手。

想像一下,你剛看完了一場突發的表演,或一場評鑑,甚至是街頭藝人,但是大家都站著,哪有放東西的地方,而展演者剛好下台一鞠躬,這時圍繞的眾人獻上了掌聲 …… 然而,你剛拍攝完照片,手上正拿著一台螢幕一點也不小的手機,你想要鼓掌,但只能發出手掌輕拍昂貴螢幕的尷尬悶響,跟手心與手心碰撞的聲音,遜色了很多。

那如何應付這種情況,又不需要放下手機呢?

如果有一個隨開隨用的網頁程式,只要拿著手機做出類似拍手的揮動,就可以發出掌聲的話,那是不是就可以解決了呢?

因此,小編就要來教大家如何用P5.js Tone.js 寫一個可以用手機三軸數據偵測揮手動作,就可以發出掌聲的網頁小程式。

1. 引入Tone.js 、解決手機與權限問題

請先在你的p5 編輯器中找到index.html,並在裡面中貼入以下網址,就可以引入Tone.js 。關於Tone.js的詳細介紹,可以參照上一篇教學

<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.9/Tone.js" integrity="sha512-nUjml8mN4CNYqBAy0ndDrd8pJV/eTtBNDsnvNtPqozx9/BccUeWSoKW14qWkQUnhuh8E3m+yra3qdzM68lqPEQ==" crossorigin="anonymous"></script>

IOS系統在網頁取得手機的資訊上的權限管的比較嚴苛,因此,必須先在網頁的程式內先克服這層問題,但這倒也不難。方法如下:

function setup() function draw() 以外,先建立一個點按畫面以許可網頁進行下一步動作的機制,作法參考網友寫的程式

let motion=false;
let ios=false;

if (typeof DeviceMotionEvent.requestPermission === 'function') {  
document.body.addEventListener('click', function() { //許可網頁進行下一步動作的機制
    DeviceMotionEvent.requestPermission().then(function() {
      console.log('DeviceMotionEvent enabled');
  motion = true;
  ios = true;
})
.catch(function(error) {
   console.warn('DeviceMotionEvent not enabled', error);
    })
  })
}

再來,不管是andriod 或是ios  ,只要是手機網頁瀏覽器播放音訊,都需要在程式內 enable Audio Context ,詳情請上這個網站上看為什麼聲音出不來。不過如果是像小編使用Tone.js的話,只要在程式內加入Tone.start(); 就可以了。

let motion=false;
let ios=false;

if (typeof DeviceMotionEvent.requestPermission === 'function') {  
document.body.addEventListener('click', function() { //許可網頁進行下一步動作的機制
Tone.start(); // ios請加在這裡
    DeviceMotionEvent.requestPermission().then(function() {
      console.log('DeviceMotionEvent enabled');
  motion = true;
  ios = true;
})
.catch(function(error) {
   console.warn('DeviceMotionEvent not enabled', error);
    })
  })
}
function setup(){
Tone.start();  // 在 function setup(){} 中也需要加 Tone.start(); ,這樣在 andriod 的瀏覽器上也能運作了

}

在手機運行瀏覽器上的程式之前,必須ㄧ定要先點按一下營幕,才會開始有動作。這是目前普遍瀏覽器的防呆機制。

好了聲音和資料偵測的權限解決,換下一步,全螢幕顯示問題。

一般 手機開了p5 editor後,畫布的形狀總是被螢幕長寬比壓縮,解決這個問題,我們需要加一行這個:

function windowResized() {// 使畫布符合手機本身長寬
resizeCanvas(windowWidth, windowHeight);}
2. 讀取檔案

創建一個 function preload(){} ,舉凡是圖檔或音檔,這個功能可以在網頁的程式都還未開始運作前先把需要的檔案都先讀入。

Tone.js 中欲播放音檔,需要先用 Tone.Players() ,這個功能相較Tone.Player()(少了一個s),可以一次讀入一個以上的音檔,並可以個別控制播放。

function preload(){
clap= new Tone.Players({
 clapping: ”data/clap.mp3",  // 輸入預錄的掌聲檔案路徑,並幫他取名字(這邊叫clapping )供日後呼叫
                       
   }).toDestination(); // 連接至聲音輸出
}
3. 觸發聲音

聲音讀入後,就是要處理觸發條件了。若要呼叫音檔播放的話,則是使用

clap.player(“clapping").start(); // 使得 clap 播放器中指定名字為「clapping」的檔案開始播放
//反之,要音檔停下的話,則是呼叫
clap.player(“clapping").stop();
//欲控制其音量的話,可以用
clap.player(“clapping").volume.value=-10; //  -10db(分貝)

我們先把要播放的內容先塞進一個 if 判斷式中

if([執行條件]){
clap.player(“clapping").volume.value= -10;
clap.player(“clapping").start();  //觸發播放拍手聲響
}

在這個程式中,觸發拍手的是以偵測手機即時的陀螺儀數據。人在拍手的時候,會往手心方向揮出一個加速度,而剛好p5.js中,有專門偵測手機三軸加速度的變數,即 accelerationX accelerationY accelerationZ

那,我們在做決定任何數據偵測之前,我們需要先觀察數據,找出在特定動作時數值變動最明顯的,再下手做數值轉換和調變。所以,我們先把三軸的加速度數據都抓出來,並顯示在畫面上,方便我們在一邊動作時一邊觀察。

background(255,255,255); //畫布背景顏色
fill(0,0,0) //顯示的字的顏色
text("device accelerations - x: " + accelerationX , width/2, 160); // 顯示 x 軸加速度的文字
text("device accelerations - y: " + accelerationY , width/2, 180); // 顯示 y 軸加速度的文字
text("device accelerations - z: " + accelerationZ , width/2, 200); // 顯示 z 軸加速度的文字

寫好了後,我們先讓程式在手機上運行。要讓程式在手機上全螢幕運行的話,請把程式上傳至 p5.editor 並按儲存,並到左上角的 File 中選擇 Share,在Share的框框中複製Fullscreen 的那行網址貼到手機瀏覽器上打開就會是全螢幕運作的模式。記得要先點螢幕一下,程式才會正式運行。

在全螢幕模式下,觀察自己搖動手機做用螢幕拍手動作的時候,會發現是影響 Z 軸的加速度變動量,並且小編發現自己用力鼓掌時, Z 軸速度變量大概都會大於3(即加速度大於3或小於-3)。我們先記著這一點,然後回到電腦,加入這個觸發條件。

if(abs(accelerationZ)>=3){ // 判定z軸速度變化量大於3時,判斷為正在拍手
  clap.player("clapping").volume.value=-10;
  clap.player(“clapping").start(); //播放拍手音效
}

設定好之後,在電腦上按儲存後(記得一定要按),後讓手機上的網頁重新整理,就會是剛剛更改好的程式。這時可以按照剛剛拍手的動作搖晃手機,就會發出音檔的聲響了。

4. 但是!?

但是,這時候大家聽聽看,音檔的聲音會因為數值變動短短的時間內疊在一起一遍遍重新播放,聲音失去了原本的質地,而且會爆音。要解決這個問題,我們必須告訴程式,在第一次播完之後才能播第二次,這樣一來聲音就不會疊在一起重複觸發。這時,我們就需要一個偵測「該音檔是否正在播放」的判定。剛好,Tone.jsTone.Players播放器有功能支援這個判定。

if(clap.player(“clapping”).state==“stopped"){ } //clapping音檔沒有在播放,則如何如何
if(clap.player(“clapping”).state==“started"){ } //clapping音檔的狀態為正在播放,則如何如何

所以我們將我們的判定播放的式子中,加入一個判定音檔停止沒在播放的條件,只有在檔案播完或沒有播的時候,才能觸發播放。

if(abs(accelerationZ)>=3){  
  if(clap.player(“clapping").state=="stopped"){ // 檔案播完或沒有播的時候,才能觸發播放
  clap.player("clapping").volume.value=-10;
  clap.player("clapping").start();
   }
}

加入這一個判定後,大家儲存檔案再重整一下手機上的網頁,就可以聽到俐落不重疊的聲音了。

完成了!大家用剛寫好的程式搖搖手機為自己鼓掌吧!

如果不清楚的話,這裡還有小編寫好的程式,大家可以拆開來看裡頭的程式細節,也可以直接在手機上玩玩看,或存著網址隨時準備拍手。 點我去p5 editor手機全螢幕運作版

這次教學是藉由P5 editor的方便性,讓我們也可以輕鬆地在自己的手機上寫讀取裝置數據的程式,探索更多好玩的體感互動。大家還想用手機感測數據做什麼有趣的互動呢 歡迎留言和我們分享!

延伸閱讀: p5.js 與 Tone.js 實作教學—— 不含任何真實貓咪的喵喵琴


參考資料:

https://p5js.org/zh-Hans/reference/#/p5/accelerationX

https://editor.p5js.org/amcc/sketches/kBndhSZER

https://tonejs.github.io/

Leave a Comment

發佈留言必須填寫的電子郵件地址不會公開。

相關文章

回到頂端