博客 / 詳情

返回

Web前端入門第 90 問:JavaScript 也能無中生有的創建音頻

網頁播放音樂這個常識應該都知道,畢竟百度 MP3 搜索可是風靡一時!

但使用瀏覽器無中生有的創建音頻,在 HTML5 規範落地之前可是一片空白。

AudioContext 的體量與 Canvas 差不了多少,一個針對圖形圖像,一個用於音頻,兩者結合起來就把 flash 給拉下了神壇~~


本文源之於一次技術研究,曾經有一個需求要用 H5 搞一個網頁 K 歌,技術難點在於要將原唱、伴唱、錄音的音頻數據進行合併,後來尋尋覓覓的找到了 AudioContext 這個 API,雖然最終沒用 H5 去實現,不過還是漲了見識!!

不廢話,直接看代碼:

<button id="button">經過我</button>

<script>
  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  (function () {
    if (!window.AudioContext) {
      alert('當前瀏覽器不支持Web Audio API');
      return;
    }

    // 按鈕元素
    var eleButton = document.getElementById('button');

    // 創建新的音頻上下文接口
    var audioCtx = new AudioContext();

    // 發出的聲音頻率數據,表現為音調的高低
    var arrFrequency = [196.00, 220.00, 246.94, 261.63, 293.66, 329.63, 349.23, 392.00, 440.00, 493.88, 523.25, 587.33, 659.25, 698.46, 783.99, 880.00, 987.77, 1046.50];

    // 音調依次遞增或者遞減處理需要的參數
    var start = 0, direction = 1;

    // 鼠標hover我們的按鈕的時候
    eleButton.addEventListener('mouseenter', function () {
      // 當前頻率
      var frequency = arrFrequency[start];
      // 如果到頭,改變音調的變化規則(增減切換)
      if (!frequency) {
        direction = -1 * direction;
        start = start + 2 * direction;
        frequency = arrFrequency[start];
      }
      // 改變索引,下一次hover時候使用
      start = start + direction;

      // 創建一個OscillatorNode, 它表示一個週期性波形(振盪),基本上來説創造了一個音調
      var oscillator = audioCtx.createOscillator();
      // 創建一個GainNode,它可以控制音頻的總音量
      var gainNode = audioCtx.createGain();
      // 把音量,音調和終節點進行關聯
      oscillator.connect(gainNode);
      // audioCtx.destination返回AudioDestinationNode對象,表示當前audio context中所有節點的最終節點,一般表示音頻渲染設備
      gainNode.connect(audioCtx.destination);
      // 指定音調的類型,其他還有square|triangle|sawtooth
      oscillator.type = 'sine';
      // 設置當前播放聲音的頻率,也就是最終播放聲音的調調
      oscillator.frequency.value = frequency;
      // 當前時間設置音量為0
      gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
      // 0.01秒後音量為1
      gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
      // 音調從當前時間開始播放
      oscillator.start(audioCtx.currentTime);
      // 1秒內聲音慢慢降低,是個不錯的停止聲音的方法
      gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 1);
      // 1秒後完全停止聲音
      oscillator.stop(audioCtx.currentTime + 1);
    });
  })();
</script>

以上代碼內容來源於大佬張鑫旭的博客:https://www.zhangxinxu.com/wordpress/2017/06/html5-web-audio-api-js-ux-voice/

注意:AudioContext 必須要在在用户有交互之後才能創建!!意思就是用户在網頁上有點擊操作之後才能開始播放音頻。

否則報錯警告:

The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.

效果預覽

可長按以下二維碼跳轉到大佬的體驗地址:

{% asset_img qrcode.jpg %}

二維碼鏈接:https://www.zhangxinxu.com/study/201706/button-hover-web-audio.html

其他示例

1、 oscillator.type 不同波形帶來的聲音效果:

https://codepen.io/gregh/pen/LxJEaj

2、又有大佬使用 AudioContext 搞出了小時候玩的遊戲音樂:

https://codepen.io/gregh/pen/xqWwqz

寫在最後

AudioContext 的 API 絕不止用來創建音頻這麼簡單,往大了想一下,Canvas 可以把 PS 搬到瀏覽器,那些專業的音頻處理軟件是不是也可以搬到線上?

看看大佬對 AudioContext 的看法:

1

參考資料
https://www.zhangxinxu.com/wordpress/2017/06/html5-web-audio-api-js-ux-voice/
https://developer.mozilla.org/zh-CN/docs/Web/API/AudioContext

user avatar ziyeliufeng 頭像 dujing_5b7edb9db0b1c 頭像 uncletong_doge 頭像 79px 頭像 lidalei 頭像 dashan_5c230d1ae1f9e 頭像 harryfyodor 頭像 geoffzhu 頭像 liuxuan_5845129fbf248 頭像 x2wen 頭像 yookoo 頭像 xiaoping_5b9bd7cd1b5c6 頭像
39 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.