web-dev-qa-db-ja.com

Web Audio APIでマイク入力ボリューム値を取得するにはどうすればよいですか?

WebオーディオAPIでマイク入力を使用していて、ボリューム値を取得する必要があります。

現在、マイクはすでに機能しています: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled

また、オーディオファイルの音量を操作する方法があることも知っています。 http://www.html5rocks.com/en/tutorials/webaudio/intro/

    // Create a gain node.
    var gainNode = context.createGain();
    // Connect the source to the gain node.
    source.connect(gainNode);
    // Connect the gain node to the destination.
    gainNode.connect(context.destination);
   // Reduce the volume.
   gainNode.gain.value = 0.5;

しかし、これら2つを組み合わせて入力ボリューム値を取得する方法は?値を操作する必要はありません。

誰か知っていますか?

22
kikkpunk

「ボリューム」を取得したい主な理由は2つあります。1)ソースの「クリップ」を検出します。つまり、信号の絶対値がプリセットレベル(通常は1.0に非常に近く)を超え、クリッピングが開始されます。 2)ユーザーに信号の大きさを感じさせます。

これらを個別に記載する理由は、最初のサンプルではすべてのサンプルを処理する必要があるためです。そうしないと、短いトランジェントを見逃す可能性があるためです。そのためには、ScriptProcessorノードを使用する必要があります。また、onaudioprocess内のバッファー内のすべてのサンプルを反復処理して、クリップレベルより上の絶対値を探す必要があります。あなたはcould RMS levelを決定するだけです-それから、各サンプルの二乗を合計し、Nで除算して平方根を計算します。onaudioprocess内からレンダリングしないでくださいただし、requestAnimationFrameでアクセスする値を設定します。

また、AnalyserNodeを使用してレベルを検出し、データを平均化することもできます。これは、上記の回答がgetAverageVolumeで行うようなものです。ただし、上記の回答はScriptProcessorの適切な使用方法ではありません。実際、スクリプトノードの処理はまったく行われず、データが渡されることさえありません。タイマーコールバックのように使用しているだけです。ビジュアルコールバックとしてrequestAnimationFrameを使用することで、FARの提供が向上します。このようにonaudioprocess内からレイアウトや視覚的なパラメーターを設定しないでください。オーディオシステムをスラッシュすることになります。クリップの検出が必要ない場合は、上からgetByteFrequencyCount/getAverageVolumeをAnalyserNodeで実行してください(ただし、Analyzerでバンドの数を最小限に抑える必要があります-64が最小です)、事前に割り当てて再利用する必要があります毎回割り当てるのではなく、Uint8Array(ガベージコレクションを増やす)。

22
cwilso

HTML 5を勉強しているときに、オーディオを再生するためのボリューム表示を行いました。

私はこの素晴らしいチュートリアルに従いました

http://www.smartjava.org/content/exploring-html5-web-audio-visualizing-sound

 // setup a analyzer
 analyser = context.createAnalyser();
 analyser.smoothingTimeConstant = 0.3;
 analyser.fftSize = 1024;

 javascriptNode = context.createScriptProcessor(2048, 1, 1);


 javascriptNode.onaudioprocess = function() {

        // get the average, bincount is fftsize / 2
        var array =  new Uint8Array(analyser.frequencyBinCount);
        analyser.getByteFrequencyData(array);
        var average = getAverageVolume(array)

         console.log('VOLUME:' + average); //here's the volume
 }

 function getAverageVolume(array) {
        var values = 0;
        var average;

        var length = array.length;

        // get all the frequency amplitudes
        for (var i = 0; i < length; i++) {
            values += array[i];
        }

        average = values / length;
        return average;
  }

[〜#〜]注[〜#〜]:マイクからのオーディオ入力で機能するかどうかわかりません

6
Netorica

少し遅れますが、引き続きお役に立てれば幸いです。

h5_get_microphone_volume

var audioContext = new (window.AudioContext || window.webkitAudioContext)()
var mediaStreamSource = null
var meter = null

if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
  navigator.mediaDevices.getUserMedia({audio: true}).then((stream) => {
    mediaStreamSource = audioContext.createMediaStreamSource(stream)
    meter = createAudioMeter(audioContext)
    mediaStreamSource.connect(meter)
  })
}

function createAudioMeter(audioContext, clipLevel, averaging, clipLag) {
  const processor = audioContext.createScriptProcessor(512)
  processor.onaudioprocess = volumeAudioProcess
  processor.clipping = false
  processor.lastClip = 0
  processor.volume = 0
  processor.clipLevel = clipLevel || 0.98
  processor.averaging = averaging || 0.95
  processor.clipLag = clipLag || 750

  // this will have no effect, since we don't copy the input to the output,
  // but works around a current Chrome bug.
  processor.connect(audioContext.destination)

  processor.checkClipping = function () {
    if (!this.clipping) {
      return false
    }
    if ((this.lastClip + this.clipLag) < window.performance.now()) {
      this.clipping = false
    }
    return this.clipping
  }

  processor.shutdown = function () {
    this.disconnect()
    this.onaudioprocess = null
  }

  return processor
}

function volumeAudioProcess(event) {
  const buf = event.inputBuffer.getChannelData(0)
  const bufLength = buf.length
  let sum = 0
  let x

  // Do a root-mean-square on the samples: sum up the squares...
  for (var i = 0; i < bufLength; i++) {
    x = buf[i]
    if (Math.abs(x) >= this.clipLevel) {
      this.clipping = true
      this.lastClip = window.performance.now()
    }
    sum += x * x
  }

  // ... then take the square root of the sum.
  const rms = Math.sqrt(sum / bufLength)

  // Now smooth this out with the averaging factor applied
  // to the previous sample - take the max here because we
  // want "fast attack, slow release."
  this.volume = Math.max(rms, this.volume * this.averaging)
  document.getElementById('audio-value').innerHTML = this.volume
}
4
Huooo