web-dev-qa-db-fra.com

Comment obtenir une valeur de volume d'entrée de microphone avec une API audio Web?

J'utilise l'entrée microphone avec une API audio Web et j'ai besoin d'obtenir la valeur du volume.

Pour l'instant, j'ai déjà le microphone pour fonctionner: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled

De plus, je sais qu’il existe une méthode permettant de manipuler le volume du fichier audio: 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;

Mais comment combiner ces deux et obtenir la valeur du volume d'entrée? J'ai juste besoin de la valeur, pas besoin de la manipuler.

Est-ce que quelqu'un sait?

20
kikkpunk

Il existe deux raisons principales pour vouloir obtenir le "volume": 1) détecter le moment où la source "extrait" - c'est-à-dire que la valeur absolue du signal dépasse un niveau préréglé, généralement très proche de 1,0, où commencer l'écrêtage. 2) donner à l'utilisateur une idée de la force de son signal.

La raison pour laquelle je les énumère séparément, c'est parce que le premier exige que vous traitiez chaque échantillon - sinon vous risqueriez de manquer un transitoire. Pour cela, vous devez utiliser un nœud ScriptProcessor et parcourir chaque échantillon de la mémoire tampon dans onaudioprocess pour rechercher des valeurs absolues supérieures au niveau de votre clip. Vous pouvez juste déterminer le niveau RMS alors aussi - vous n'avez qu'à additionner les carrés de chaque échantillon, diviser par N et prendre la racine carrée. NE RENDRE PAS depuis un processus unique, cependant - définissez les valeurs auxquelles vous accédez sur requestAnimationFrame.

Vous pouvez également utiliser un AnalyserNode pour effectuer la détection de niveau et simplement faire la moyenne des données, un peu comme ce que la réponse ci-dessus fait dans getAverageVolume. Cependant, la réponse ci-dessus N’EST PAS une bonne utilisation de ScriptProcessor. En fait, elle ne traite aucun traitement du noeud de script, pas même la transmission des données, mais l’utilise comme un rappel de minuterie. Vous seriez beaucoup mieux servi en utilisant requestAnimationFrame en tant que rappel visuel; Ne définissez jamais de configuration ou de paramètres visuels depuis un processus audio comme celui-ci, ou vous suppliez de bloquer votre système audio. Si vous n'avez pas besoin de détection de clip, faites simplement getByteFrequencyCount/getAverageVolume ci-dessus sur un AnalyserNode (mais vous devriez minimiser le nombre de bandes dans Analyzer - 64 est le minimum, je pense), et pré-allouer et réutiliser un Uint8Array plutôt que de l'allouer à chaque fois (ce qui amplifiera le garbage collection).

19
cwilso

J'ai étudié le volume d'un fichier audio lorsque j'étudiais HTML 5.

J'ai suivi ce bon tutoriel 

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;
  }

NOTE: Je ne sais tout simplement pas si cela fonctionnera sur une entrée audio provenant d'un microphone

6
Mp de la Vega

Bien qu'il soit un peu tard, j'espère toujours vous aider.

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
}
1
Huooo