feat: complete Phase 10 - add phase correlation, LUFS, and audio statistics
Implemented remaining Phase 10 analysis tools: **Phase Correlation Meter (10.3)** - Real-time stereo phase correlation display - Pearson correlation coefficient calculation - Color-coded indicator (-1 to +1 scale) - Visual feedback: Mono-like, Good Stereo, Wide Stereo, Phase Issues **LUFS Loudness Meter (10.3)** - Momentary, Short-term, and Integrated LUFS measurements - Simplified K-weighting approximation - Vertical bar display with -70 to 0 LUFS range - -23 LUFS broadcast standard reference line - Real-time history tracking (10 seconds) **Audio Statistics (10.4)** - Project info: track count, duration, sample rate, channels, bit depth - Level analysis: peak, RMS, dynamic range, headroom - Real-time buffer analysis from all tracks - Color-coded warnings for clipping and low headroom **Integration** - Added 5-button toggle in master column (FFT, SPEC, PHS, LUFS, INFO) - All analyzers share consistent 192px width layout - Theme-aware styling for light/dark modes - Compact button labels for space efficiency 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -6,6 +6,9 @@ import { PlaybackControls } from './PlaybackControls';
|
||||
import { MasterControls } from '@/components/controls/MasterControls';
|
||||
import { FrequencyAnalyzer } from '@/components/analysis/FrequencyAnalyzer';
|
||||
import { Spectrogram } from '@/components/analysis/Spectrogram';
|
||||
import { PhaseCorrelationMeter } from '@/components/analysis/PhaseCorrelationMeter';
|
||||
import { LUFSMeter } from '@/components/analysis/LUFSMeter';
|
||||
import { AudioStatistics } from '@/components/analysis/AudioStatistics';
|
||||
import { ThemeToggle } from '@/components/layout/ThemeToggle';
|
||||
import { CommandPalette } from '@/components/ui/CommandPalette';
|
||||
import { GlobalSettingsDialog } from '@/components/settings/GlobalSettingsDialog';
|
||||
@@ -49,7 +52,7 @@ export function AudioEditor() {
|
||||
const [settingsDialogOpen, setSettingsDialogOpen] = React.useState(false);
|
||||
const [exportDialogOpen, setExportDialogOpen] = React.useState(false);
|
||||
const [isExporting, setIsExporting] = React.useState(false);
|
||||
const [analyzerView, setAnalyzerView] = React.useState<'frequency' | 'spectrogram'>('frequency');
|
||||
const [analyzerView, setAnalyzerView] = React.useState<'frequency' | 'spectrogram' | 'phase' | 'lufs' | 'stats'>('frequency');
|
||||
|
||||
const { addToast } = useToast();
|
||||
|
||||
@@ -1067,37 +1070,72 @@ export function AudioEditor() {
|
||||
</div>
|
||||
|
||||
{/* Analyzer Toggle */}
|
||||
<div className="flex gap-1 bg-muted/20 border border-border/50 rounded-md p-1 max-w-[192px] mx-auto">
|
||||
<div className="grid grid-cols-5 gap-0.5 bg-muted/20 border border-border/50 rounded-md p-0.5 max-w-[192px] mx-auto">
|
||||
<button
|
||||
onClick={() => setAnalyzerView('frequency')}
|
||||
className={`flex-1 px-2 py-1 rounded text-[10px] font-bold uppercase tracking-wider transition-all ${
|
||||
className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
|
||||
analyzerView === 'frequency'
|
||||
? 'bg-accent text-accent-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
title="Frequency Analyzer"
|
||||
>
|
||||
FFT
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAnalyzerView('spectrogram')}
|
||||
className={`flex-1 px-2 py-1 rounded text-[10px] font-bold uppercase tracking-wider transition-all ${
|
||||
className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
|
||||
analyzerView === 'spectrogram'
|
||||
? 'bg-accent text-accent-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
title="Spectrogram"
|
||||
>
|
||||
Spectrum
|
||||
SPEC
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAnalyzerView('phase')}
|
||||
className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
|
||||
analyzerView === 'phase'
|
||||
? 'bg-accent text-accent-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
title="Phase Correlation"
|
||||
>
|
||||
PHS
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAnalyzerView('lufs')}
|
||||
className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
|
||||
analyzerView === 'lufs'
|
||||
? 'bg-accent text-accent-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
title="LUFS Loudness"
|
||||
>
|
||||
LUFS
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setAnalyzerView('stats')}
|
||||
className={`px-1 py-1 rounded text-[9px] font-bold uppercase tracking-wider transition-all ${
|
||||
analyzerView === 'stats'
|
||||
? 'bg-accent text-accent-foreground shadow-sm'
|
||||
: 'text-muted-foreground hover:text-foreground'
|
||||
}`}
|
||||
title="Audio Statistics"
|
||||
>
|
||||
INFO
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Analyzer Display */}
|
||||
<div className="flex-1 min-h-[360px] flex items-start justify-center">
|
||||
<div className="w-[192px]">
|
||||
{analyzerView === 'frequency' ? (
|
||||
<FrequencyAnalyzer analyserNode={masterAnalyser} />
|
||||
) : (
|
||||
<Spectrogram analyserNode={masterAnalyser} />
|
||||
)}
|
||||
{analyzerView === 'frequency' && <FrequencyAnalyzer analyserNode={masterAnalyser} />}
|
||||
{analyzerView === 'spectrogram' && <Spectrogram analyserNode={masterAnalyser} />}
|
||||
{analyzerView === 'phase' && <PhaseCorrelationMeter analyserNode={masterAnalyser} />}
|
||||
{analyzerView === 'lufs' && <LUFSMeter analyserNode={masterAnalyser} />}
|
||||
{analyzerView === 'stats' && <AudioStatistics tracks={tracks} />}
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
||||
Reference in New Issue
Block a user