mozilla

製作一個 Web 上的音調產生器

這是一個簡單的音調產生器的範例。requestSoundData() 是產生音頻樣本的函式,這個函式在經過某個特定的時間間隔會透過 setInterval() 被呼叫。mozWriteAudio() 是在被呼叫時,把樣本寫入音頻串流的函式。為了確保總是有可以播放的樣本,這個範例設置了一個 500 ms 的緩衝。mozCurrentSampleOffset() 是一個用來知道正在被播放的樣本所在位置的函式,這的函式被這個範例用來確保我們填進緩衝的總是正在被播放後的 500 ms。

<!DOCTYPE html>
<html>
  <head>
    <title>JavaScript 音頻寫入範例</title>
  </head>
  <body>
    <input type="text" size="4" id="freq" value="440"><label for="hz">Hz</label>
    <button onclick="start()">play</button>
    <button onclick="stop()">stop</button>

    <script type="text/javascript">      
      function AudioDataDestination(sampleRate, readFn) {
        // 音頻輸出的初使化
        var audio = new Audio();
        audio.mozSetup(1, sampleRate);

        var currentWritePosition = 0;
        var prebufferSize = sampleRate / 2; // 緩衝 500ms
        var tail = null;

        // 這個函數會被定期呼叫以填充音頻輸出緩衝
        setInterval(function() {
          var written;
          // 看看之前也沒有留下未被寫入的資料
          if(tail) {  
            written = audio.mozWriteAudio(tail);
            currentWritePosition += written;
            if(written < tail.length) {
              // 並非所有資料都被寫入了,把剩下的存下來...
              tail = tail.slice(written);
              return; // ... 並結束這個函式
            }
            tail = null;
          }

          // 看看是不是有需要再加新資料至音頻輸出
          var currentPosition = audio.mozCurrentSampleOffset();
          var available = currentPosition + prebufferSize - currentWritePosition;
          if(available > 0) {
            // 從回撥函式(callback)要一些音效資料
            var soundData = new Float32Array(parseFloat(available));
            readFn(soundData);

            // 寫這些資料
            written = audio.mozWriteAudio(soundData);
            if(written < soundData.length) {
              // 不是所有資料都被寫入了,存下剩下的部份。
              tail = soundData.slice(written);
            }
            currentWritePosition += written;
          }
        }, 100);
      }

      // 控制並製造聲音

      var frequency = 0, currentSoundSample;
      var sampleRate = 44100;

      function requestSoundData(soundData) {
        if (!frequency) { 
          return; // 已被靜音
        }

        var k = 2* Math.PI * frequency / sampleRate;
        for (var i=0, size=soundData.length; i<size; i++) {
          soundData[i] = Math.sin(k * currentSoundSample++);
        }        
      }

      var audioDestination = new AudioDataDestination(sampleRate, requestSoundData);

      function start() {
        currentSoundSample = 0;
        frequency = parseFloat(document.getElementById("freq").value);
      }

      function stop() {
        frequency = 0;
      }
  </script>
  </body>
</html>

Document Tags and Contributors

Contributors to this page: Kennyluck
最近更新: Kennyluck,