fix: use Float32Array for accurate full-range level measurement

Switched from Uint8Array to Float32Array for level monitoring
to get accurate, full-precision audio measurements.

The Problem:
- getByteTimeDomainData() uses Uint8Array (0-255)
- Byte conversion: (value - 128) / 128 has asymmetric range
- Positive peaks: (255-128)/128 = 0.992 (not full 1.0)
- Precision loss from byte quantization
- Mastered tracks with peaks at 0dBFS only showed ~50%

The Solution:
- Switched to getFloatTimeDomainData() with Float32Array
- Returns actual sample values directly in -1.0 to +1.0 range
- No conversion needed, no precision loss
- Accurate representation of audio peaks

Changes Applied:
- useMultiTrackPlayer: Float32Array with analyser.fftSize samples
- useRecording: Float32Array with analyser.fftSize samples
- Peak detection: Math.abs() on float values directly

Benefits:
 Full 0-100% range for properly mastered audio
 Higher precision (32-bit float vs 8-bit byte)
 Symmetric range (-1.0 to +1.0, not -1.0 to ~0.992)
 Accurate metering for professional audio files

Now mastered tracks with peaks at 0dBFS will correctly show
~100% on the meters instead of being capped at 50%.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-18 15:21:31 +01:00
parent 3e6fbda755
commit a0ce83a654
2 changed files with 12 additions and 12 deletions

View File

@@ -61,15 +61,15 @@ export function useMultiTrackPlayer(tracks: Track[], masterVolume: number = 1) {
const track = tracksRef.current[index];
if (!track) return;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(dataArray);
const dataArray = new Float32Array(analyser.fftSize);
analyser.getFloatTimeDomainData(dataArray);
// Calculate peak level (more responsive than RMS for visual meters)
// Calculate peak level using float data (-1 to +1 range)
let peak = 0;
for (let i = 0; i < dataArray.length; i++) {
const normalized = Math.abs((dataArray[i] - 128) / 128);
if (normalized > peak) {
peak = normalized;
const abs = Math.abs(dataArray[i]);
if (abs > peak) {
peak = abs;
}
}

View File

@@ -71,19 +71,19 @@ export function useRecording(): UseRecordingReturn {
if (!analyserRef.current) return;
const analyser = analyserRef.current;
const dataArray = new Uint8Array(analyser.frequencyBinCount);
const dataArray = new Float32Array(analyser.fftSize);
const updateLevel = () => {
if (!isMonitoringRef.current) return;
analyser.getByteTimeDomainData(dataArray);
analyser.getFloatTimeDomainData(dataArray);
// Calculate peak level (more responsive than RMS for visual meters)
// Calculate peak level using float data (-1 to +1 range)
let peak = 0;
for (let i = 0; i < dataArray.length; i++) {
const normalized = Math.abs((dataArray[i] - 128) / 128);
if (normalized > peak) {
peak = normalized;
const abs = Math.abs(dataArray[i]);
if (abs > peak) {
peak = abs;
}
}