2025-08-21 22:43:11 +09:00
|
|
|
"""
|
|
|
|
|
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
|
2025-08-21 23:39:53 +09:00
|
|
|
from font_manager import safe_title
|
2025-08-21 22:43:11 +09:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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)')
|
2025-08-21 23:39:53 +09:00
|
|
|
ax.set_title(safe_title(os.path.basename(file_path)))
|
2025-08-21 22:43:11 +09:00
|
|
|
|
|
|
|
|
# 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
|
|
|
|
|
"""
|
2025-08-21 23:39:53 +09:00
|
|
|
return f"""Track: {safe_title(song_name)}
|
2025-08-21 22:43:11 +09:00
|
|
|
BPM: {bpm:.1f}
|
|
|
|
|
Max Amplitude: {max_amplitude:.3f}
|
|
|
|
|
Avg Amplitude: {avg_amplitude:.3f}"""
|