AnalyserNode.getFloatFrequencyData всегда возвращает -Infinity

Хорошо, поэтому я пытаюсь определить интенсивность (в дБ) образцов аудиофайла, записанного браузером пользователя.

Мне удалось записать его и воспроизвести через элемент HTML. Но когда я пытаюсь использовать этот элемент в качестве источника и подключить его к AnalyserNode, AnalyserNode.getFloatFrequencyData всегда возвращает массив, полный -Infinity, getByteFrequencyData всегда возвращает нули, getByteTimeDomainData заполнен 128.

Вот мой код:

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source;

var analyser = audioCtx.createAnalyser();

var bufferLength = analyser.frequencyBinCount;
var data = new Float32Array(bufferLength);

mediaRecorder.onstop = function(e) {
  var blob = new Blob(chunks, { 'type' : 'audio/ogg; codecs=opus' });

  chunks = [];
  var audioURL = window.URL.createObjectURL(blob);
  // audio is an HTML audio element
  audio.src = audioURL;

  audio.addEventListener("canplaythrough", function() {
      source = audioCtx.createMediaElementSource(audio);

      source.connect(analyser);
      analyser.connect(audioCtx.destination);

      analyser.getFloatFrequencyData(data);
      console.info(data);
  });
}

Есть идеи, почему AnalyserNode ведет себя так, как будто источник пуст / отключен? Я также попытался поставить поток в качестве источника во время записи, с тем же результатом.

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
793
3

Ответы 3

Если исходный файл из другого домена? Это приведет к ошибке createMediaElementSource.

Создается линией var audioURL = window.URL.createObjectURL(blob); с данными из MediaRecorder.

Divarrek 28.10.2018 15:45

Вам нужно получить аудиофайл и декодировать аудиобуфер. URL-адрес источника звука также должен находиться в том же домене или иметь правильные заголовки CORS (как упоминал Энтони).

Примечание. Замените <FILE-URI> на путь к вашему файлу в примере ниже.

var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
var source;
var analyser = audioCtx.createAnalyser();
var button = document.querySelector('button');
var freqs;
var times;


button.addEventListener('click', (e) => {
  fetch("<FILE-URI>", {
    headers: new Headers({
      "Content-Type" : "audio/mpeg"
    })
  }).then(function(response){
    return response.arrayBuffer()
  }).then((ab) => {
    audioCtx.decodeAudioData(ab, (buffer) => {
      source = audioCtx.createBufferSource();
      source.connect(audioCtx.destination)
      source.connect(analyser);
      source.buffer = buffer;
      source.start(0);
      viewBufferData();
    });
  });
});

// Watch the changes in the audio buffer
function viewBufferData() {
  setInterval(function(){
    freqs = new Uint8Array(analyser.frequencyBinCount);
    times = new Uint8Array(analyser.frequencyBinCount);
    analyser.smoothingTimeConstant = 0.8;
    analyser.fftSize = 2048;
    analyser.getByteFrequencyData(freqs);
    analyser.getByteTimeDomainData(times);
    console.info(freqs)
    console.info(times)
  }, 1000)
}

этот код работал у меня на firefox, но не на chrome? Любые идеи

MAS 01.10.2020 13:53

Не без дополнительной информации. Я предполагаю, что есть проблема совместимости с вашей версией Chrome? Если вы заглянете в консоль, то найдете хотя бы ключ к разгадке того, почему она не работает.

Richard 02.10.2020 14:58

это действительно было!

MAS 02.10.2020 15:00

Я столкнулся с той же проблемой, благодаря некоторым вашим фрагментам кода, я заставил ее работать со своей стороны (приведенный ниже код является машинописным и не будет работать в браузере на момент написания):

audioCtx.decodeAudioData(this.result as ArrayBuffer).then(function (buffer: AudioBuffer) { 
      soundSource = audioCtx.createBufferSource();
      soundSource.buffer = buffer;
      //soundSource.connect(audioCtx.destination); //I do not need to play the sound
      soundSource.connect(analyser);
      soundSource.start(0);

      setInterval(() => {
         calc(); //In here, I will get the analyzed data with analyser.getFloatFrequencyData 
      }, 300); //This can be changed to 0.
      // The interval helps with making sure the buffer has the data

Некоторое объяснение (я все еще новичок, когда дело доходит до API веб-аудио, поэтому мое объяснение может быть неправильным или неполным): Анализатор должен уметь анализировать определенную часть вашего звукового файла. В этом случае я создаю AudioBufferSoundNode, содержащий буфер, который я получил при декодировании аудиоданных. Я скармливаю буфер источнику, который в конечном итоге можно будет скопировать внутри Анализатора. Однако без обратного вызова интервала буфер никогда не кажется готовым, а проанализированные данные содержат -Inifinity (что, как я предполагаю, является отсутствием звука, так как ему нечего читать) в каждом индексе массива. Вот почему интервал есть. Он анализирует данные каждые 300 мс.

Надеюсь, это кому-то поможет!

Другие вопросы по теме