Как получить правильные амплитуды (без воспроизведения) сэмплов аудиотрека с помощью веб-аудио 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) на обоих компьютерах, единственное отличие - это аппаратное обеспечение. Код, приведенный в моем посте, работает как положено.