mmpSearch/assets/js/creations/waveform.js

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();
}