Как получить правильные амплитуды (без воспроизведения) сэмплов аудиотрека с помощью веб-аудио API

Я провел несколько экспериментов с объемными данными сэмплов, предоставленными мне we b audio api, и оказалось, что они отличаются от данных, полученных из других программ, таких как audasity, например. Он показывает длительность аудио около 40 секунд, если мы возьмем длину массива делителей выборок к частоте дискретизации (leftChannel.length/44100 в моем случае), а также где Audacity показывает громкие сэмплы в аудио, мой сценарий показывает тихий (иногда почти бесшумный)). И я сыграл пьесы, о которых мой сценарий сообщил как тихие в смелости, и определенно громкий звук.

Таким образом, вопрос: правильный ли мой способ найти амплитуды аудиосэмплов? А что не так с моим кодом?

Я прочитал ветку о создании формы волны для аудиотрека Создайте форму волны полной дорожки с помощью Web Audio API, и есть хороший пример того, что я использовал, поэтому вот мой код:

(function($) {

  window.AudioContext = window.AudioContext || window.webkitAudioContext;
  var context = new window.AudioContext(); // Create audio container
  var audioData;
  var checkPoint = 21; //this is point in seconds just for debugging, remove later!!
  function decode(audioData) {
    try{
        context.decodeAudioData(audioData,
        function(decoded){
            drawSound(decoded);
            playAudio(decoded);
        },
        function(){ // do nothing here
        });
    } catch(e) {
        console.log('decode exception',e.message);
    }
  }

  function drawSound(buffer) {
    var leftChannel = buffer.getChannelData(0);
    console.log('audio duration: ' + leftChannel.length/44100 + ' sec');
    for (var i = 0; i < leftChannel.length; i++) {
      var volume = leftChannel[i];
      //draw(volume, i);
      
      //this is just for debugging, remove later!!
      if (Math.abs(i - checkPoint * 44100) < 100) {
        console.log(leftChannel[i]);
      }
      
    }    
  }

  function playAudio(buffer) {
    console.log('start playing audio');
    var audioTrack = context.createBufferSource();
    audioTrack.connect(context.destination);
    audioTrack.buffer = buffer;
    audioTrack.start();
  }

  $(document).ready(function() {
    $('body').append($('<input type="text" id="checkpoint" />'));
    $('#checkpoint').change(function() {
      checkPoint = $(this).val();
    });
    $('body').append($('<input type="file" id="audiofile" />'));
    $('input[type="file"]').change(function() {
      var reader = new FileReader();
      reader.onload = function(e) {
        audioData = this.result;
        decode(audioData);
      };
      reader.readAsArrayBuffer(this.files[0]);      
    });
    
  });
})(jQuery);
<html>
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
  </head>
  <body>
    
  </body>
</html>

3 ответа

Решение

Благодаря Raymond Toy мне удалось решить эту проблему. Похоже, что результат, возвращаемый buffer.getChannelData(0), зависит от частоты дискретизации компьютерной аудиокарты (которую можно найти в context.sampleRate). И если вы хотите найти длину трека, вы должны сделать это так:

var samples = buffer.getChannelData(0);
var duration = samples/context.sampleRate;

И смещение выборки от начала в секундах:

var sample = samples[i];
var offsetInSeconds = i/context.sampleRate

Моя ошибка заключалась в том, что я использовал частоту дискретизации аудиотрека mp3 в формулах, и это вызывало ошибки на компьютере с разной частотой дискретизации аудиокарты.

Как заметил Раймонд Той, если вам нужна только длительность звука, вы можете сделать это еще проще:

var duration = buffer.duration;

Если вы считаете, что это ошибка в Chrome, отправьте сообщение об ошибке по адресу crbug.com/new. И предоставьте один аудиотрек, который дает разные результаты и подробную информацию о разных машинах.

Также обратите внимание, что в chrome для декодирования файлов используется ffmpeg. Расшифрованный файл может отличаться по длине от отваги.

Я сделал более тщательные измерения и больше тестирований и обнаружил, что в моем сценарии нет ошибок, НО!! api web audio дает результаты, равные Audasity как для длины аудиотрека, так и для амплитуд на одном из моих компьютеров (как в Chrome, так и в Firefox) и неверные результаты на другом компьютере (опять же независимо от браузера), поэтому я заключаю, что api web audio использует некоторые низкоуровневые функции, зависящие от процессора, потому что у меня одинаковая ОС (windows 7) на обоих компьютерах, единственное отличие - это аппаратное обеспечение. Код, приведенный в моем посте, работает как положено.

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