fix: switch from RMS to peak detection for more accurate level meters

Changed level calculation from RMS to peak detection to show
more realistic and responsive meter values.

The Problem:
- RMS calculation produced values typically in 0-30% range
- Audio signals have low average RMS (0.1-0.3 for music)
- Meters appeared broken, never reaching higher levels

The Solution:
- Switched to peak detection (max absolute value)
- Peaks now properly show 0-100% range
- More responsive to transients and dynamics
- Matches typical DAW meter behavior

Algorithm Change:
Before (RMS):
  rms = sqrt(sum(normalized²) / length)

After (Peak):
  peak = max(abs(normalized))

Applied to Both:
- Recording input level monitoring (useRecording)
- Playback output level monitoring (useMultiTrackPlayer)

Benefits:
 Full 0-100% range utilization
 More responsive visual feedback
 Accurate representation of audio peaks
 Consistent with professional audio software

🤖 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:15:16 +01:00
parent a157172e3d
commit 8367cbf6e7
2 changed files with 15 additions and 12 deletions

View File

@@ -64,14 +64,16 @@ export function useMultiTrackPlayer(tracks: Track[], masterVolume: number = 1) {
const dataArray = new Uint8Array(analyser.frequencyBinCount);
analyser.getByteTimeDomainData(dataArray);
// Calculate RMS level
let sum = 0;
// Calculate peak level (more responsive than RMS for visual meters)
let peak = 0;
for (let i = 0; i < dataArray.length; i++) {
const normalized = (dataArray[i] - 128) / 128;
sum += normalized * normalized;
const normalized = Math.abs((dataArray[i] - 128) / 128);
if (normalized > peak) {
peak = normalized;
}
}
const rms = Math.sqrt(sum / dataArray.length);
levels[track.id] = rms;
levels[track.id] = peak;
});
setTrackLevels(levels);

View File

@@ -78,15 +78,16 @@ export function useRecording(): UseRecordingReturn {
analyser.getByteTimeDomainData(dataArray);
// Calculate RMS level
let sum = 0;
// Calculate peak level (more responsive than RMS for visual meters)
let peak = 0;
for (let i = 0; i < dataArray.length; i++) {
const normalized = (dataArray[i] - 128) / 128;
sum += normalized * normalized;
const normalized = Math.abs((dataArray[i] - 128) / 128);
if (normalized > peak) {
peak = normalized;
}
}
const rms = Math.sqrt(sum / dataArray.length);
setState((prev) => ({ ...prev, inputLevel: rms }));
setState((prev) => ({ ...prev, inputLevel: peak }));
animationFrameRef.current = requestAnimationFrame(updateLevel);
};