Files
uj-mastering-master/plotting_engine.py
T
Mikkeli Matlock 4337a31b80 Implement threading, logging, and CJK font support
Major improvements to GUI stability and internationalization:

- Fix GUI freezing by implementing threaded audio analysis
  - Add AudioAnalysisWorker thread for background processing
  - Progress signals with percentage updates
  - Thread-safe communication via Qt signals

- Add comprehensive CLI logging system
  - 5 log levels: ERROR, WARN, INFO, DEBUG, TRACE
  - Command line control: --log-level, --log-file
  - Real-time feedback during analysis operations

- Implement CJK font fallback system
  - FontManager with 3-tier fallback (custom → system → default)
  - Cross-platform CJK font detection (Windows/macOS/Linux)
  - Licensing-safe fonts/ directory with gitignored font files
  - Setup utility and comprehensive documentation

- Fix numpy array formatting issue with BPM detection
- Add progress indicators for long-running operations
- Preserve fonts directory structure with placeholder file

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-21 23:39:53 +09:00

80 lines
2.5 KiB
Python

"""
Audio visualization plotting engine.
Separates plotting logic from audio processing for clean GUI integration.
"""
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors
import matplotlib.cm as cm
from matplotlib.figure import Figure
import os
from font_manager import safe_title
class PlottingEngine:
"""Handles all matplotlib visualization logic for audio analysis."""
@staticmethod
def create_power_analysis_figure(times, rms_array, file_path, figsize=(10, 4)):
"""
Creates a matplotlib Figure for power analysis visualization.
Args:
times: Array of time points
rms_array: RMS power values over time
file_path: Path to the audio file for title
figsize: Figure size tuple
Returns:
matplotlib.figure.Figure: Ready-to-embed figure
"""
# Determine color scale based on headroom detection
local_max_power = np.max(rms_array)
if local_max_power > 0.3:
norm = mcolors.Normalize(vmin=0, vmax=0.6)
maxpower = 0.6
else:
norm = mcolors.Normalize(vmin=0, vmax=0.3)
maxpower = 0.3
# Create figure and axis
fig = Figure(figsize=figsize, facecolor='white')
ax = fig.add_subplot(111)
# Color map
cmap = cm.autumn
# Plot power levels as colored bars
ax.set_ylim(0., maxpower)
for i in range(len(times)-1):
ax.fill_between(times[i:i+2], 0, rms_array[0][i],
color=cmap(norm(rms_array[0][i])), edgecolor='none')
# Add colorbar
sm = cm.ScalarMappable(cmap=cmap, norm=norm)
sm.set_array([])
cbar = fig.colorbar(sm, ax=ax, label='RMS Power')
# Labels and title
ax.set_ylabel('Power')
ax.set_xlabel('Time (seconds)')
ax.set_title(safe_title(os.path.basename(file_path)))
# Tight layout for better appearance in GUI
fig.tight_layout()
return fig
@staticmethod
def create_metadata_display_text(song_name, bpm, max_amplitude, avg_amplitude):
"""
Creates formatted text for metadata display.
Returns:
str: Formatted metadata text
"""
return f"""Track: {safe_title(song_name)}
BPM: {bpm:.1f}
Max Amplitude: {max_amplitude:.3f}
Avg Amplitude: {avg_amplitude:.3f}"""