DEV Community

張旭豐
張旭豐

Posted on

敲水杯奏音樂:用瀏覽器麥克風做互動聲音

你有沒有在樂團暖身的時候敲過水杯?

玻璃杯裝不同量的水,敲下去的聲音都不一樣。水越少,聲音越高。這個現象,其實就是物理:水量影響震動頻率。

你可能以為這種「敲什麼像什麼」的遊戲,要靠專業設備才能做出來。

其實不用。一個 HTML 檔、瀏覽器、還有你的電腦麥克風,就夠了。


這是什麼

一個免安裝的瀏覽器互動玩具。你對著麥克風敲水杯,系統即時判斷聲音落在哪個音高區間,畫面跟著變色、動畫跳動,聲音馬上變成視覺。

原理:瀏覽器裡的耳朵

瀏覽器給了我們 getUserMedia 這個功能。它可以叫瀏覽器去打開你電腦或手機的麥克風,然後即時把聲音變成數字資料流。

拿到資料流之後,我們用「快速傅立葉轉換」把聲音拆開,看裡面有哪些頻率。

三個杯子,各裝不同的水量,敲下去,畫面就告訴你:這是低音、中音、還是高音。

完整範例:只要一個 HTML 檔

把以下內容存成 glass.html,用瀏覽器打開就能玩:

<!DOCTYPE html>
<html lang="zh">
<head>
  <meta charset="UTF-8">
  <title>敲水杯奏音樂</title>
  <style>
    body { font-family: sans-serif; text-align: center; padding: 40px; transition: background 0.3s; }
    #start { padding: 12px 24px; font-size: 18px; cursor: pointer; }
    #zone { font-size: 48px; font-weight: bold; margin: 30px; color: #fff; }
    .hint { color: #888; margin-top: 20px; }
  </style>
</head>
<body>
  <h1>敲水杯奏音樂</h1>
  <button id="start">開啟麥克風</button>
  <div id="zone"></div>
  <p class="hint">裝不同量水的三個杯子,敲敲看</p>

  <script>
    const startBtn = document.getElementById('start');
    const zoneEl = document.getElementById('zone');

    startBtn.addEventListener('click', async () => {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const audioCtx = new AudioContext();
      const source = audioCtx.createMediaStreamSource(stream);
      const analyser = audioCtx.createAnalyser();
      analyser.fftSize = 2048;
      source.connect(analyser);
      startBtn.disabled = true;
      startBtn.textContent = '聆聽中…';
      listen(analyser, audioCtx);
    });

    function listen(analyser, audioCtx) {
      const buffer = new Uint8Array(analyser.frequencyBinCount);

      function update() {
        analyser.getByteFrequencyData(buffer);

        let maxVal = 0;
        let maxIndex = 0;
        for (let i = 0; i < buffer.length; i++) {
          if (buffer[i] > maxVal) {
            maxVal = buffer[i];
            maxIndex = i;
          }
        }

        const freq = maxIndex * audioCtx.sampleRate / analyser.fftSize;
        let zone = '靜音';
        let color = '#111';

        if (maxVal > 50) {
          if (freq < 400) {
            zone = '💧 低音';
            color = '#1a1a2e';
          } else if (freq < 1200) {
            zone = '🌊 中音';
            color = '#16213e';
          } else {
            zone = '✨ 高音';
            color = '#0f3460';
          }
        }

        zoneEl.textContent = zone;
        document.body.style.background = color;
        requestAnimationFrame(update);
      }
      update();
    }
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

讓阿哲玩起來的設定

顏色回饋:低音是深藍,中音是靛藍,高音是亮白。

動畫回饋:每個音高觸動不同的幾何圖形——低音是方塊沈下去,中音是圓圈彈跳,高音是星星散開。

音符回饋:在畫面上即時標示「這個聲音接近 Do」「這個接近 Mi」。

Q&A

Q:一定要水杯嗎?
A:不用。敲桌面、敲筆筒、敲任何東西都可以。

Q:環境很吵怎麼辦?
A:靠近你要敲的物體,麥克風就只會收到那個聲音。

拿三個杯子,各裝三分之一、二分之一、滿水的量。敲一次,看看畫面告訴你什麼。那就是「你的音樂,你的水杯,你的瀏覽器」。

Top comments (0)