65 lines
2.2 KiB
JavaScript
65 lines
2.2 KiB
JavaScript
// js/waveform.js
|
|
|
|
/**
|
|
* Desenha a forma de onda de um AudioBuffer em um elemento Canvas.
|
|
* Pode desenhar apenas um segmento específico do buffer.
|
|
* @param {HTMLCanvasElement} canvas - O elemento canvas onde o desenho será feito.
|
|
* @param {AudioBuffer} audioBuffer - O buffer de áudio decodificado da faixa.
|
|
* @param {string} color - A cor da forma de onda (ex: '#2ecc71').
|
|
* @param {number} [offset=0] - O tempo em segundos de onde começar a desenhar no AudioBuffer.
|
|
* @param {number} [duration] - A duração em segundos do segmento a ser desenhado.
|
|
*/
|
|
export function drawWaveform(canvas, audioBuffer, color, offset = 0, duration) {
|
|
if (!canvas || !audioBuffer) return;
|
|
|
|
const ctx = canvas.getContext('2d');
|
|
const width = canvas.width;
|
|
const height = canvas.height;
|
|
const channelData = audioBuffer.getChannelData(0);
|
|
const sampleRate = audioBuffer.sampleRate;
|
|
|
|
// Se a duração não for fornecida, usa a duração total a partir do offset
|
|
const finalDuration = duration || (audioBuffer.duration - offset);
|
|
|
|
// Calcula os índices de início e fim no array de dados do áudio
|
|
const startIndex = Math.floor(offset * sampleRate);
|
|
const endIndex = Math.floor((offset + finalDuration) * sampleRate);
|
|
const totalSamplesInSegment = endIndex - startIndex;
|
|
|
|
const step = Math.ceil(totalSamplesInSegment / width);
|
|
const amp = height / 2;
|
|
|
|
ctx.clearRect(0, 0, width, height);
|
|
ctx.strokeStyle = color;
|
|
ctx.lineWidth = 1;
|
|
ctx.beginPath();
|
|
|
|
// Desenha a linha do meio (zero amplitude)
|
|
ctx.moveTo(0, amp);
|
|
ctx.lineTo(width, amp);
|
|
|
|
for (let i = 0; i < width; i++) {
|
|
let min = 1.0;
|
|
let max = -1.0;
|
|
|
|
for (let j = 0; j < step; j++) {
|
|
// --- CORREÇÃO CRÍTICA AQUI ---
|
|
// Calcula o índice da amostra considerando o startIndex do segmento
|
|
const sampleIndex = startIndex + (i * step) + j;
|
|
if (sampleIndex < channelData.length) {
|
|
const datum = channelData[sampleIndex];
|
|
if (datum < min) min = datum;
|
|
if (datum > max) max = datum;
|
|
}
|
|
}
|
|
|
|
const x = i;
|
|
// Ajusta o desenho para ser centrado verticalmente
|
|
const y_max = (1 - max) * amp;
|
|
const y_min = (1 - min) * amp;
|
|
|
|
ctx.moveTo(x, y_max);
|
|
ctx.lineTo(x, y_min);
|
|
}
|
|
ctx.stroke();
|
|
} |