Reference lines:
- Kept per metric (dict keyed by metric_id) so switching metrics and coming back
preserves them, instead of clearing on every switch
- Spectrogram lines read/edit/drag in Hz: the renderer installs Hz<->row-index
transforms (the heatmap y-axis is a row index), so value, label, the edit
dialog, and the new-line default all speak frequency. Curve metrics stay
identity. Round-trip verified (1000 Hz -> row -> 1000 Hz)
- Line label and drag-readback always in the metric's natural units
Controls:
- Relative-time abs/rel is now a checkbox toggle, not a dropdown
- Removed the font control panel; UI font is locked to M PLUS 1 Code @ 10pt via
font_manager.apply_fixed_font (system-default fallback). Deleted
font_control_widget.py
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reference lines:
- Side-panel cluster (ref_line_widget.py): list of lines with Add/Edit/Remove/
Clear and a properties dialog (value, colour, line style, tag)
- Lines own their state as RefLineProps (held by MainWindow), drawn with a
triangle drag-handle; dragging writes the value back and refreshes the list
- Replaces the old centre-only add-and-drag-the-whole-line approach
Comparison:
- Time-axis mode selector: Absolute (seconds) vs Relative (% of each track's own
length), so a long track and a short one line up by song position. Pure view
transform (plotspec.apply_x_mode), no recompute
- Overlaid different-length tracks now autorange their x union in absolute mode
instead of clipping to the first track's span
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- SpectrogramMetric: log-frequency STFT power heatmap over time, magma
colormap, -80 dB floor. Adaptive hop caps time bins at ~4000 so long
tracks stay responsive on redraw; N_FFT=4096 keeps low-freq resolution.
- master_core: load audio at native sample rate (librosa.load sr=None)
instead of librosa's 22050 Hz default, so the full band up to the
file's own nyquist (~22 kHz at 44.1 kHz) is analysed. ~2x heavier on
44.1/48 kHz files, by design.
- metrics: shared _show_axis_extents helper forces each axis's exact
min/max onto the tick list with compact labels (_fmt_tick), so the
true range is always readable -- notably the spectrogram's 22 kHz top,
which otherwise sits unlabelled between log-scale decade ticks. Applied
to all metric renders.
- Docs: README + CLAUDE updated for the new metric, native-rate loading,
and axis-readability behaviour.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Three new metrics plug into the existing Metric registry. All inherit
the async compute path, so first-use is non-blocking and subsequent
switches hit the per-(file, metric) cache.
- CrestFactorMetric: 20*log10(peak/RMS) per 1 s window, 0.25 s hop.
Uses cumsum-of-squares for O(N) RMS. Reference lines at 12 dB
(roomy) and 6 dB (heavily limited).
- PSRMetric: sample-peak (dBFS) minus short-term LUFS over the same
3 s window as LUFSMetric, so the two plots line up. Reference lines
at 10 LU (good punch) and 4 LU (squashed).
- TruePeakMetric: ITU-R BS.1770 oversampled true peak via
scipy.signal.resample_poly at 4x over 250 ms / 100 ms windows.
data["integrated_tp_db"] carries the track-wide max.
- LUFSMetric now also computes Meter.loudness_range and surfaces it
in the plot legend alongside the integrated value.
- Shared _to_dbfs helper floors 20*log10 at _EPS so silent windows
don't explode.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduce a Metric ABC (compute on worker thread, render on GUI thread)
with a METRICS registry, and refactor the analysis pipeline around it.
RMS power (ported), raw waveform, and BS.1770 LUFS (via pyloudnorm) ship
as the initial three; new metrics drop in by appending to METRICS.
- metrics.py: Metric ABC + RMSPowerMetric, WaveformMetric (locked to
+/-1.1 y-range for float headroom), LUFSMetric (short-term 3 s window
+ integrated value, with streaming-target reference line).
- plot_control_widget.py: metric selector dropdown + Refresh Plot button
(moved out of FontControlWidget).
- analysis_results_manager.py: AnalysisResult caches the AudioFile and a
per-metric data dict; new MetricComputeWorker runs metric switches off
the GUI thread via metricComputeStarted/metricReady/metricComputeError
signals, so LUFS on a 12-minute track no longer stalls the UI.
- main.py: all redraw paths funnel through one _render_or_request helper;
stale-result guards keep slow computes from overwriting fresh selections.
- plotting_engine.py removed (metadata text moved onto AnalysisResult;
figure construction lives in each Metric).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Reflect current implementation status with complete GUI and font system
- Update roadmap with prioritized development plan focusing on plot control widgets
- Reorganize future goals into urgent/short-term/mid-long term categories
- Add comprehensive feature overview and usage instructions
- Clarify next priority: plot control system clustering
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add open file button for direct audio file selection
- Implement clustered FontControlWidget with font selector, size slider, and refresh controls
- Add auto-regeneration of matplotlib plots when fonts change
- Enhance FontManager with system font discovery and startup selection logic
- Replace individual font selector with comprehensive font control interface
- Support both custom fonts and system font candidates with proper prioritization
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
Major refactor from popup-based to persistent PyQt5 interface:
- Extract plotting logic from AudioFile class into separate PlottingEngine
- Create AudioVisualizationWidget with embedded matplotlib canvas
- Add AnalysisResultsManager as bridge between processing and GUI
- Replace simple drag-drop widget with professional splitter layout
- Preserve legacy batch processing mode with execution guard
Features:
- Drag-and-drop audio analysis (.mp3/.wav/.flac support)
- File list with metadata display (BPM, amplitudes, track info)
- Persistent visualization area (no more matplotlib popups)
- Multi-file support with click-to-view functionality
- Threading-ready architecture for future background processing
Technical improvements:
- Clean separation of concerns (analysis/visualization/GUI)
- Qt signal-slot communication pattern
- Modular component design ready for multithreading
- Proper import guards prevent legacy code interference
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Added CLAUDE.md with detailed project documentation and roadmap
- Enhanced README.md with usage section for command line and GUI modes
- Updated with Claude Code credit
- Improved master_core.py with better song name handling and BPM display
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>