Генерация статического сигнала с помощью webaudio
Я пытаюсь сгенерировать статический сигнал, как в приложениях для редактирования аудио с помощью webaudio и canvas. Сейчас я загружаю mp3, создаю буфер и перебираю данные, возвращаемые getChannelData.
Проблема в том... Я не очень понимаю, что возвращается.
- Что возвращается getChannelData - подходит ли он для сигнала?
- Как настроить (размер выборки?), Чтобы получить один пик == одну секунду?
Почему ~50% значений отрицательные?
ctx.decodeAudioData(req.response, function(buffer) { buf = buffer; src = ctx.createBufferSource(); src.buffer = buf; //create fft fft = ctx.createAnalyser(); var data = new Uint8Array(samples); fft.getByteFrequencyData(data); bufferL = buf.getChannelData(0) for(var i = 0; i<buf.length; i++){ n = bufferL[i*(1000)] gfx.beginPath(); gfx.moveTo(i +0.5, 300); gfx.lineTo(i +0.5, 300 + (-n*100)); gfx.stroke();
Что я генерирую:
Что я хотел бы создать:
Спасибо
1 ответ
Я написал пример, чтобы сделать это точно - https://github.com/cwilso/Audio-Buffer-Draw. Это довольно упрощенная демонстрация - вам придется делать масштабирование самостоятельно, но идея есть.
1) Да, getChannelData возвращает выборки аудиобуфера для этого канала. 2) Ну, это зависит от того, насколько часты пики в вашем образце, и это не обязательно соответствует. Образец отрисовки, который я сделал, действительно уменьшает масштаб (это "шаг" метода), но вы, вероятно, захотите оптимизировать его для своего сценария. 3) Половина значений отрицательна, поскольку сэмплы звучат между -1 и +1. Звуковые волны - это волна положительного и отрицательного давления; вот почему "тишина" - это плоская линия посередине, а не внизу.
Код:
var audioContext = new AudioContext();
function drawBuffer( width, height, context, buffer ) {
var data = buffer.getChannelData( 0 );
var step = Math.ceil( data.length / width );
var amp = height / 2;
for(var i=0; i < width; i++){
var min = 1.0;
var max = -1.0;
for (var j=0; j<step; j++) {
var datum = data[(i*step)+j];
if (datum < min)
min = datum;
if (datum > max)
max = datum;
}
context.fillRect(i,(1+min)*amp,1,Math.max(1,(max-min)*amp));
}
}
function initAudio() {
var audioRequest = new XMLHttpRequest();
audioRequest.open("GET", "sounds/fightclub.ogg", true);
audioRequest.responseType = "arraybuffer";
audioRequest.onload = function() {
audioContext.decodeAudioData( audioRequest.response,
function(buffer) {
var canvas = document.getElementById("view1");
drawBuffer( canvas.width, canvas.height, canvas.getContext('2d'), buffer );
} );
}
audioRequest.send();
}
window.addEventListener('load', initAudio );