OscillatorNode

Baseline 已廣泛支援

此特性已相當成熟,可在許多裝置和瀏覽器版本上使用。自 ⁨2015 年 7 月⁩以來,各瀏覽器均已提供此特性。

OscillatorNode 介面表示一個週期性波形,例如正弦波。它是一個 AudioScheduledSourceNode 音訊處理模組,用於建立給定波形的指定頻率——實際上是一個恆定的音調。

EventTarget AudioNode AudioScheduledSourceNode OscillatorNode
輸入數量 0
輸出數量 1
通道計數模式 max
聲道數 2 (在預設計數模式下未使用)
通道解釋 揚聲器

建構函式

OscillatorNode()

建立一個新的 OscillatorNode 物件例項,可以選擇提供一個物件來指定節點的 屬性 的預設值。或者,您可以使用 BaseAudioContext.createOscillator() 工廠方法;請參閱 建立 AudioNode

例項屬性

還繼承了其父類 AudioScheduledSourceNode 的屬性。

OscillatorNode.frequency

一個 a-rate AudioParam,表示振動的頻率(以赫茲為單位)(儘管返回的 AudioParam 是隻讀的,但它表示的值不是)。預設值為 440 Hz(標準的中央 A 音)。

OscillatorNode.detune

一個 a-rate AudioParam,表示振動的失諧(以音分為單位)(儘管返回的 AudioParam 是隻讀的,但它表示的值不是)。預設值為 0。

OscillatorNode.type

一個字串,指定要播放的波形形狀;它可以是許多標準值之一,或者 custom,用於使用 PeriodicWave 來描述自定義波形。不同的波形會產生不同的音調。標準值是 "sine""square""sawtooth""triangle""custom"。預設值為 "sine"

例項方法

還繼承了其父類 AudioScheduledSourceNode 的方法。

OscillatorNode.setPeriodicWave()

設定一個 PeriodicWave,該波形描述了用於替代標準波形之一的週期性波形;呼叫此方法會將 type 設定為 custom

AudioScheduledSourceNode.start()

指定開始播放音調的確切時間。

AudioScheduledSourceNode.stop()

指定停止播放音調的時間。

事件

還繼承了其父類 AudioScheduledSourceNode 的事件。

示例

使用 OscillatorNode

以下示例展示瞭如何使用 AudioContext 建立一個振盪器節點並開始播放其音調。有關實際應用示例,請檢視我們的 Violent Theremin 演示相關程式碼請參見 app.js)。

js
// create web audio api context
const audioCtx = new AudioContext();

// create Oscillator node
const oscillator = audioCtx.createOscillator();

oscillator.type = "square";
oscillator.frequency.setValueAtTime(440, audioCtx.currentTime); // value in hertz
oscillator.connect(audioCtx.destination);
oscillator.start();

不同的振盪器節點型別

四個內建的振盪器 型別sinesquaretrianglesawtooth。它們是振盪器生成的波形的形狀。有趣的事實:這些是大多數合成器的預設設定,因為它們是易於電子生成的波形。此示例可視化了不同型別在不同頻率下的波形。

html
<div class="controls">
  <label for="type-select">
    Oscillator type
    <select id="type-select">
      <option>sine</option>
      <option>square</option>
      <option>triangle</option>
      <option>sawtooth</option>
    </select>
  </label>

  <label for="freq-range">
    Frequency
    <input
      type="range"
      min="100"
      max="800"
      step="10"
      value="250"
      id="freq-range" />
  </label>
  <button data-playing="init" id="play-button">Play</button>
</div>

<canvas id="wave-graph"></canvas>

程式碼分為兩部分:第一部分,我們設定了聲音相關的部分。

js
const typeSelect = document.getElementById("type-select");
const frequencyControl = document.getElementById("freq-range");
const playButton = document.getElementById("play-button");

const audioCtx = new AudioContext();
const osc = new OscillatorNode(audioCtx, {
  type: typeSelect.value,
  frequency: frequencyControl.valueAsNumber,
});
// Rather than creating a new oscillator for every start and stop
// which you would do in an audio application, we are just going
// to mute/un-mute for demo purposes - this means we need a gain node
const gain = new GainNode(audioCtx);
const analyser = new AnalyserNode(audioCtx, {
  fftSize: 1024,
  smoothingTimeConstant: 0.8,
});
osc.connect(gain).connect(analyser).connect(audioCtx.destination);

typeSelect.addEventListener("change", () => {
  osc.type = typeSelect.value;
});

frequencyControl.addEventListener("input", () => {
  osc.frequency.value = frequencyControl.valueAsNumber;
});

playButton.addEventListener("click", () => {
  if (audioCtx.state === "suspended") {
    audioCtx.resume();
  }

  if (playButton.dataset.playing === "init") {
    osc.start(audioCtx.currentTime);
    playButton.dataset.playing = "true";
    playButton.innerText = "Pause";
  } else if (playButton.dataset.playing === "false") {
    gain.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.2);
    playButton.dataset.playing = "true";
    playButton.innerText = "Pause";
  } else if (playButton.dataset.playing === "true") {
    gain.gain.linearRampToValueAtTime(0.0001, audioCtx.currentTime + 0.2);
    playButton.dataset.playing = "false";
    playButton.innerText = "Play";
  }
});

至於第二部分,我們使用上面建立的 AnalyserNode 將波形繪製在畫布上。

js
const dpr = window.devicePixelRatio;
const w = 500 * dpr;
const h = 300 * dpr;
const canvasEl = document.getElementById("wave-graph");
canvasEl.width = w;
canvasEl.height = h;
const canvasCtx = canvasEl.getContext("2d");

const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
analyser.getByteTimeDomainData(dataArray);

// draw an oscilloscope of the current oscillator
function draw() {
  analyser.getByteTimeDomainData(dataArray);

  canvasCtx.fillStyle = "white";
  canvasCtx.fillRect(0, 0, w, h);

  canvasCtx.lineWidth = 4.0;
  canvasCtx.strokeStyle = "black";
  canvasCtx.beginPath();

  const sliceWidth = (w * 1.0) / bufferLength;
  let x = 0;

  for (let i = 0; i < bufferLength; i++) {
    const v = dataArray[i] / 128.0;
    const y = (v * h) / 2;
    if (i === 0) {
      canvasCtx.moveTo(x, y);
    } else {
      canvasCtx.lineTo(x, y);
    }
    x += sliceWidth;
  }

  canvasCtx.lineTo(w, h / 2);
  canvasCtx.stroke();

  requestAnimationFrame(draw);
}

draw();

警告:此示例會發出噪音!

規範

規範
Web Audio API
# OscillatorNode

瀏覽器相容性

另見