iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
0

§d24§ 庭院聲幾許?木魚的冥想! Tone.js 載入 mp3 咚咚作響!

demo

0. 今日工事

  • 載入聲音檔案
  • Tone.Player
  • 敲木魚

https://ithelp.ithome.com.tw/upload/images/20180113/201078283VCuYC93gr.jpg

1. 載入聲音檔案

很久以前,§d7§ 全頻率震動!終於買到CDPRO2!Web Audio API 的原力!裡面就有提到使用 browser 提供的 Web Audio API,就可以把音訊檔案載入記憶體裡面(稱之 Buffer),並播放出來。當時後解釋過,當音訊檔案的資料輸入到 Buffer 之後,可以當作一個 Source Node 來使用。但完成整個下載、載入、接線、播放的過程,要落落長的一大段才能真的產生聲音,我可能不想處理那麼瑣碎的部分,尤其是當 Tone 已經幫我們 handle 好的時候!

2. Tone.Player

說實話,當初考慮 Tone 與 Howler 兩個 framework 的時候(§d8§ 全頻率震動!派對音響工程!為何選 Tone.js 當作 Audio Framework? )主要的原因是因為 Tone 很強調合成聲音與音樂創作的邏輯,而 Howler 只能夠播放音樂。但是這此的使用情境,我突然想到 Howler 好像比較單純,我也沒有需要額外的功能。只有 Filter 跟音量之類的效果。

不久發現,我又錯了!Howler 居然連 Filter 都沒有,誇張。搜尋整個 readme 連一點點影子都看不到。好吧,我還是得繼續用 Tone 。而 Tone 裡面,關於聲音檔案的物件叫做Player。使用方式相當直覺,只要送進 url 並告訴他啟動馬上可以一切就緒。

const player = new Tone.Player("./path/to/sample.mp3").toMaster();
player.autostart = true; //play as soon as the buffer is loaded

除了基本的播放出來之外,Tone.Player還提供onload的 callback,可以在 buffer 全部載入完畢之後呼叫。設定loop也有很多方便的功能,相當齊全。

但是我覺得比較大的一個缺點:Player沒有實作一些 loop 的播放途中的 callback,像是可以在每次檔案播到 5.3 秒的時候會固定呼叫。會希望有這個功能是因為想要在聲音上面更動態的配合畫面,而不需要一直拿 realtime 的 FFT 出來分析。

3. 敲木魚

既然可以直接用檔案了,當然是去偉大的 google 上面找聲音檔案來玩啦。找了一下子,就發現了可愛的木魚聲音。

但是除了木魚之外,感覺還需要一點 ambient 的聲響。反正就是一種嗡嗡嗡或是嗯嗯嗯哼哼的聲音。兩個加在一起就對味了!

第一步,webpack 的設定記得要加上 mp3 檔案的 loader。我使用的是最簡單的 file-loader,因為他就是直接幫你找到對的 url,就是這麼方便:

// webpack.common.config.js
loaders: [
  ...

  {
    test: /\.mp3$/,
    exclude: /(node_modules|bower_components)/,
    loader: 'file-loader?name=[name].[ext]'
  },
  ...
],

在 Three 主程式裡面先加入檔案與Tone.Player

// index.js
import { Player } from 'tone';
import woodenFish from './sound/wf.mp3';
import meditation from './sound/med.mp3';

並建立兩個 instances,並將meditationPlayer給保存起來,等下要進行控制:

let meditationPlayer;
function initSound() {
  const p1 = new Player(woodenFish).toMaster();
  p1.autostart = true;
  p1.loop = true;

  const p2 = new Player(meditation).toMaster();
  p2.autostart = true;
  p2.loop = true;
  p2.fadeOut = '1.0';
  p2.fadeIn = '45.0';

  meditationPlayer = p2;
}

onMouseWheel裡面,之前的進度本來只是將石頭進行轉動,大概長這個樣子:

function onMouseWheel(e) {
  if (mouseOnRock) {
    controls.enabled = false;
    const dY = e.deltaY * 0.02;
    rockAngle += dY;
    rock.rotation.y += dY;
  } else {
    controls.enabled = true;
  }
}

現在同時將兩個參數配合在一起,需要考慮到聲音並非無限地去變大與變小,還是會希望告訴使用的人現在參數已經轉不動了的限制,所以給他一個 -30dB1dB的範圍吧:

function onMouseWheel(e) {
  if (mouseOnRock) {
    controls.enabled = false;
    const dY = e.deltaY * 0.02;

    const { value } = meditationPlayer.volume;
    const vNew = value + dY * 5;
    if (vNew > -30 && vNew < 1) {
      rockAngle += dY;
      rock.rotation.y += dY;
      meditationPlayer.volume.value = vNew;
    }
  } else {
    controls.enabled = true;
  }
}

來吧,滾動滾輪滾石頭,嗡嗡嗚嗡嗡嗡。

demo
source code

https://ithelp.ithome.com.tw/upload/images/20180113/20107828BLvoVYniPC.png

4. 請愛CYBER の audio / VISUAL

差不多了,差不多先生,差不多是天生。接下來就是,新的世界。去找尋看看吧。
主題是CYBER の audio / VISUAL,其實也隱性的包涵了一個概念,那就是「創意編程」(creative coding),而要發揮創意的關鍵其中之一就是順暢的工具。我們不能想像,當設計師需要自己寫一套 Adobe Creative Suite 才能進行後面的發想的話,那會有多恐怖。所以該來的會來,p5.js已經悄然的降臨這個世界...

關於作者

Vibert Thio

致力於將對於技術的深度研究轉化為新型態藝術創作的能量,並思考技術的拓展/侷限與其對於藝術論述/呈現的影響。專長為數位藝術創作、音像程式設計、互動設計,喜愛即時運算的臨場感與不可預測。


上一篇
§d23§ 庭院聲幾許?木魚的冥想!Three.js 裝備 Tone.js 前的基本互動!
下一篇
§d25§ 詩化源代碼!Coding 為何 Creative?p5.js 的誕生與辯證!
系列文
aesthEtic,CYBERの audio / VISUAL,網頁中的聲音與影像研究30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言