mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-24 14:55:37 +00:00
fix waveform not being the right length.
This commit is contained in:
@@ -74,22 +74,36 @@ export class WaveformGenerator {
|
||||
|
||||
const arrayBuffer = await response.arrayBuffer();
|
||||
const decoded = await this.audioContext.decodeAudioData(arrayBuffer);
|
||||
|
||||
const adaptivePeakCount = Math.max(
|
||||
peakCount,
|
||||
Math.floor(decoded.duration * 500)
|
||||
);
|
||||
const channels: Float32Array[] = [];
|
||||
for (let i = 0; i < decoded.numberOfChannels; i++) {
|
||||
// We slice to transfer the underlying buffer to the worker
|
||||
channels.push(decoded.getChannelData(i).slice());
|
||||
}
|
||||
|
||||
const peaks = await this.computePeaksWithWorker(channels, peakCount);
|
||||
const peaks = await this.computePeaksWithWorker(channels, adaptivePeakCount);
|
||||
|
||||
// Robust Normalization: Use 99.5th percentile to avoid being squashed by a single loud spike/pop
|
||||
let max = 0;
|
||||
for (let i = 0; i < peaks.length; i++) {
|
||||
if (peaks[i] > max) max = peaks[i];
|
||||
const sortedPeaks = [...peaks].sort((a, b) => a - b);
|
||||
const percentileIndex = Math.floor(sortedPeaks.length * 0.995);
|
||||
const robustMax = sortedPeaks[percentileIndex] || 0;
|
||||
|
||||
// Fallback to absolute max if the percentile is zero (very quiet file)
|
||||
if (robustMax === 0) {
|
||||
for (let i = 0; i < peaks.length; i++) {
|
||||
if (peaks[i] > max) max = peaks[i];
|
||||
}
|
||||
} else {
|
||||
max = robustMax;
|
||||
}
|
||||
|
||||
if (max > 0) {
|
||||
for (let i = 0; i < peaks.length; i++) {
|
||||
peaks[i] /= max;
|
||||
peaks[i] = Math.min(1.0, peaks[i] / max);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,12 +24,17 @@ workerScope.onmessage = (e: MessageEvent<WaveformWorkerRequest>) => {
|
||||
const firstChannel = channels[0];
|
||||
const result = new Float32Array(samples);
|
||||
const total = firstChannel.length;
|
||||
const blockSize = total / samples;
|
||||
|
||||
for (let i = 0; i < samples; i++) {
|
||||
const start = Math.floor((i * total) / samples);
|
||||
const end = Math.floor(((i + 1) * total) / samples);
|
||||
const start = Math.floor(i * blockSize);
|
||||
const end = Math.min(total, Math.floor((i + 1) * blockSize));
|
||||
|
||||
let max = 0;
|
||||
for (let j = start; j < end; j++) {
|
||||
// Ensure we check at least one sample even if blockSize < 1
|
||||
const actualEnd = Math.max(start + 1, end);
|
||||
|
||||
for (let j = start; j < actualEnd && j < total; j++) {
|
||||
for (let c = 0; c < channels.length; c++) {
|
||||
const val = Math.abs(channels[c][j]);
|
||||
if (val > max) max = val;
|
||||
|
||||
@@ -75,31 +75,32 @@ function AudioWaveformComponent({
|
||||
const { peaks: peakData, durationMs } = peaks;
|
||||
if (durationMs <= 0 || peakData.length === 0) return;
|
||||
|
||||
const rawVisibleStartMs = segmentStartMs ?? range.start;
|
||||
const rawVisibleEndMs = segmentEndMs ?? range.end;
|
||||
const msPerBin = durationMs / peakData.length;
|
||||
const visibleStartMs =
|
||||
msPerBin > 0 ? Math.round(rawVisibleStartMs / msPerBin) * msPerBin : rawVisibleStartMs;
|
||||
const visibleEndMs =
|
||||
msPerBin > 0 ? Math.round(rawVisibleEndMs / msPerBin) * msPerBin : rawVisibleEndMs;
|
||||
// Use raw values for smooth zooming/panning (no snapping)
|
||||
const visibleStartMs = segmentStartMs ?? range.start;
|
||||
const visibleEndMs = segmentEndMs ?? range.end;
|
||||
const visibleDurationMs = visibleEndMs - visibleStartMs;
|
||||
|
||||
if (visibleDurationMs <= 0) return;
|
||||
|
||||
const midY = height / 2;
|
||||
|
||||
ctx.beginPath();
|
||||
|
||||
for (let px = 0; px < width; px++) {
|
||||
const t = visibleStartMs + (px / width) * visibleDurationMs;
|
||||
const exactIndex = Math.max(
|
||||
0,
|
||||
Math.min(peakData.length - 1, (t / durationMs) * (peakData.length - 1)),
|
||||
);
|
||||
|
||||
// If the timeline time is beyond the actual audio duration, we draw nothing (flat line)
|
||||
if (t < 0 || t > durationMs) continue;
|
||||
|
||||
const exactIndex = (t / durationMs) * (peakData.length - 1);
|
||||
const leftIndex = Math.floor(exactIndex);
|
||||
const rightIndex = Math.min(peakData.length - 1, leftIndex + 1);
|
||||
const mix = exactIndex - leftIndex;
|
||||
|
||||
let amplitude = peakData[leftIndex] * (1 - mix) + peakData[rightIndex] * mix;
|
||||
|
||||
if (normalize) amplitude = Math.sqrt(Math.max(0, amplitude));
|
||||
amplitude = Math.max(0, Math.min(1, amplitude * gain));
|
||||
|
||||
const barHeight = amplitude * midY * 0.85;
|
||||
|
||||
ctx.moveTo(px, midY - barHeight);
|
||||
|
||||
Reference in New Issue
Block a user