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:
@@ -64,14 +64,16 @@ export function useMultiTrackPlayer(tracks: Track[], masterVolume: number = 1) {
|
|||||||
const dataArray = new Uint8Array(analyser.frequencyBinCount);
|
const dataArray = new Uint8Array(analyser.frequencyBinCount);
|
||||||
analyser.getByteTimeDomainData(dataArray);
|
analyser.getByteTimeDomainData(dataArray);
|
||||||
|
|
||||||
// Calculate RMS level
|
// Calculate peak level (more responsive than RMS for visual meters)
|
||||||
let sum = 0;
|
let peak = 0;
|
||||||
for (let i = 0; i < dataArray.length; i++) {
|
for (let i = 0; i < dataArray.length; i++) {
|
||||||
const normalized = (dataArray[i] - 128) / 128;
|
const normalized = Math.abs((dataArray[i] - 128) / 128);
|
||||||
sum += normalized * normalized;
|
if (normalized > peak) {
|
||||||
|
peak = normalized;
|
||||||
}
|
}
|
||||||
const rms = Math.sqrt(sum / dataArray.length);
|
}
|
||||||
levels[track.id] = rms;
|
|
||||||
|
levels[track.id] = peak;
|
||||||
});
|
});
|
||||||
|
|
||||||
setTrackLevels(levels);
|
setTrackLevels(levels);
|
||||||
|
|||||||
@@ -78,15 +78,16 @@ export function useRecording(): UseRecordingReturn {
|
|||||||
|
|
||||||
analyser.getByteTimeDomainData(dataArray);
|
analyser.getByteTimeDomainData(dataArray);
|
||||||
|
|
||||||
// Calculate RMS level
|
// Calculate peak level (more responsive than RMS for visual meters)
|
||||||
let sum = 0;
|
let peak = 0;
|
||||||
for (let i = 0; i < dataArray.length; i++) {
|
for (let i = 0; i < dataArray.length; i++) {
|
||||||
const normalized = (dataArray[i] - 128) / 128;
|
const normalized = Math.abs((dataArray[i] - 128) / 128);
|
||||||
sum += normalized * normalized;
|
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);
|
animationFrameRef.current = requestAnimationFrame(updateLevel);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user