检测浏览器中实时音频输入的音调

时间:2019-02-07 05:08:25

标签: javascript google-chrome

如何检测浏览器中实时音频输入的音调?

以下代码将为您提供1,024个频率值。但是,我不知道如何从此变为实际的音高(例如A#)。

const audioContext = new window.AudioContext();
const analyser = audioContext.createAnalyser();

navigator.getUserMedia(
  { audio: true },
  stream => {
    audioContext.createMediaStreamSource(stream).connect(analyser);

    const dataArray = new Uint8Array(analyser.frequencyBinCount);

    analyser.getByteTimeDomainData(dataArray);

    // Log the contents of the analyzer ever 500ms. 
    setInterval(() => {
      console.log(dataArray.length);
    }, 500);
  },
  err => console.log(err)
);

1 个答案:

答案 0 :(得分:0)

您当前正在访问的是时域数据,不能用于检索便笺(这似乎是您想要的)。

您想要的是使用AnalyserNode.get[XXX]FrequencyData的频域,您可以从中获得更大或更安静的频率。

但是,由于大多数声音是由和声构成的,因此您无法从麦克风中检索到 note 所播放的内容,此外,我们只能使用有限的分辨率,而且您不仅会无法从麦克风中检索到音符,甚至也无法从虚拟振荡器中获得音符。

下面的示例来自this Q/Aexamples from MDN

const canvasCtx = canvas.getContext('2d');
const WIDTH = canvas.width = 500;
const HEIGHT = canvas.height = 150;

const audioCtx = new (window.AudioContext || window.webkitAudioContext);
const analyser = audioCtx.createAnalyser();

const nyquist = audioCtx.sampleRate / 2;

// highest precision
analyser.fftSize = 32768;

const bufferLength = analyser.frequencyBinCount;
const dataArray = new Uint8Array(bufferLength);
const osc = audioCtx.createOscillator();
osc.frequency.value = 400;
osc.connect(analyser);
osc.connect(audioCtx.destination);

range.oninput = e => {
  osc.frequency.value = range.value;
};

if(!audioCtx.state || audioCtx.state === 'running') {
  begin();
}
else {
  log.textContent = 'click anywhere to begin';
  onclick = e => {
    onclick = null;
    begin()
  }
}

function begin() {
  osc.start(0);
  draw();
}

function draw() {
  requestAnimationFrame(draw);

  // get the Frequency Domain
  analyser.getByteFrequencyData(dataArray);

  canvasCtx.fillStyle = 'rgb(0, 0, 0)';
  canvasCtx.fillRect(0, 0, WIDTH, HEIGHT);

  const barWidth = (WIDTH / bufferLength) * 2.5;
  let max_val = -Infinity;
  let max_index = -1;
  let x = 0;
  for(let i = 0; i < bufferLength; i++) {
    let barHeight = dataArray[i];
    if(barHeight > max_val) {
      max_val = barHeight;
      max_index = i;
    }

    canvasCtx.fillStyle = 'rgb(' + (barHeight+100) + ',50,50)';
    canvasCtx.fillRect(x,HEIGHT-barHeight/2,barWidth,barHeight/2);
    x += barWidth;
  }
  log.textContent = `loudest freq: ${max_index * (nyquist / bufferLength)}
real value: ${range.value}`;
}
#log{display: inline-block; margin:0 12px}
#canvas{display: block;}
<input id="range" type="range" min="0" max="1000" value="400"><pre id="log"></pre>
<canvas id="canvas"></canvas>