Pytanie Jak uzyskać wartość głośności wejścia mikrofonowego za pomocą interfejsu web audio?


Używam wejścia mikrofonowego z interfejsem web audio i potrzebuję uzyskać wartość głośności.

W tej chwili mam już mikrofon do pracy: http://updates.html5rocks.com/2012/09/Live-Web-Audio-Input-Enabled

Ponadto wiem, że istnieje metoda manipulująca głośnością pliku 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;

Ale jak połączyć te dwa i uzyskać wartość objętości wejściowej? Po prostu potrzebuję wartości, nie potrzebuję manipulować nią.

Czy ktoś wie?


18
2018-01-21 01:39


pochodzenie




Odpowiedzi:


Istnieją dwa główne powody, dla których chcesz uzyskać "tom": 1) wykrywa, kiedy źródło "zacina" - tj. Bezwzględna wartość sygnału przekracza ustalony poziom, zwykle bardzo blisko 1,0, gdzie zacznie ścinać. 2) dać użytkownikowi wyczucie, jak głośny jest ich sygnał.

Powód, dla którego osobno je wymieniam, jest taki, że pierwszy wymaga przetworzenia każdej próbki - ponieważ w przeciwnym razie można pominąć krótki okres przejściowy. W tym celu będziesz musiał użyć węzła ScriptProcessor i będziesz musiał powtórzyć każdą próbkę w buforze znajdującym się wewnątrz obiektu, aby wyszukać bezwzględne wartości powyżej poziomu klipu. ty mógłby po prostu określ poziom RMS - po prostu zsumuj kwadraty każdej próbki, podziel przez N i weź pierwiastek kwadratowy. NIE RÓWNIEJ renderowania z zewnątrz - ustawienia wartości, do których uzyskujesz dostęp na requestAnimationFrame.

Można również użyć węzła AnalyserNode do wykrycia poziomu i po prostu wyrównać dane, tak jak w powyższej odpowiedzi w getAverageVolume. Jednak powyższa odpowiedź NIE jest dobrym zastosowaniem ScriptProcessora - w rzeczywistości nie wykonuje żadnego przetwarzania węzła skryptu, nawet nie przekazując danych, po prostu używa go jak wywołania zwrotnego licznika czasu. Byłbyś lepiej obsłużony przez użycie requestAnimationFrame jako wizualnego wywołania zwrotnego; nigdy nie ustawiaj w takudoprocessingu układu ani parametrów wizualnych w ten sposób, lub prosisz, aby zmiażdżyć twój system audio. Jeśli nie potrzebujesz wykrywania klipów, po prostu wykonaj getByteFrequencyCount / getAverageVolume od góry na węźle AnalyserNode (ale powinieneś zminimalizować liczbę pasm w analizatorze - 64 to chyba minimum) i powinieneś wstępnie przydzielić i użyć ponownie a Uint8Array zamiast przydzielać go za każdym razem (to wzmocni zbieranie śmieci).


18
2018-01-21 22:48



Czy jest jakiś szybki sposób na uzyskanie jeszcze najwyższego poziomu? Spodziewałbym się, że to była podstawowa funkcja AnalyserNode (oprócz RMS). Przebiega on przez wszystkie kłopoty FFT, ale nie daje podstaw niezbędnych do prostego miernika szczytowego lub RMS. Czy ScriptProcessorNode jest najszybszym sposobem? Jeśli tak, to obawiam się, że jest zbyt wolno, by można go było używać na więcej niż kilku kanałach jednocześnie. Wzywanie swojej wiedzy i nadzieja na cud. :-) - Brad
Nope, ScriptProcessor to obecnie (do wykrywania szczytowych klipów). AudioWorkers przyspieszy to, oczywiście, ale jeszcze nie będzie wysyłki. - cwilso


Kiedy studiowałem HTML 5, zrobiłem wyświetlacz głośności dla odtwarzanego dźwięku.

Poszedłem za tym świetnym tutorialem

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

UWAGA: Po prostu nie wiem, czy to zadziała, bo dźwięk pochodzi z mikrofonu


6
2018-01-21 01:56





Chociaż jest trochę za późno, nadal mam nadzieję, że ci pomogę.

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
}

0
2017-08-15 13:09