import Cocoa /// 5 个球形波动画,由实时音频 RMS 电平驱动 final class WaveformView: NSView { private let weights: [Float] = [0.5, 0.8, 1.0, 0.75, 0.55] private var dots: [NSView] = [] private var smoothedLevels: [Float] = [0, 0, 0, 0, 0] private var decayTimer: Timer? private var rawLevel: Float = 0 private let dotSize: CGFloat = 4 private let maxExtra: CGFloat = 28 private let spacing: CGFloat = 6 private let silenceThreshold: Float = 0.02 override init(frame: NSRect) { super.init(frame: frame) setupDots() wantsLayer = true } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupDots() { dots.forEach { $0.removeFromSuperview() } dots.removeAll() let totalWidth = CGFloat(weights.count) * dotSize + CGFloat(weights.count - 1) * spacing let startX = (bounds.width - totalWidth) / 2 for (index, _) in weights.enumerated() { let x = startX + CGFloat(index) * (dotSize + spacing) let dot = NSView(frame: NSRect(x: x, y: 0, width: dotSize, height: dotSize)) dot.wantsLayer = true dot.layer?.cornerRadius = dotSize / 2 dot.layer?.backgroundColor = NSColor.white.withAlphaComponent(0.9).cgColor addSubview(dot) dots.append(dot) } decayTimer?.invalidate() decayTimer = Timer.scheduledTimer(withTimeInterval: 0.04, repeats: true) { [weak self] _ in self?.updateDecay() } } func updateLevel(_ level: Float) { rawLevel = level for i in 0.. smoothedLevels[i] { smoothedLevels[i] = smoothedLevels[i] * 0.55 + target * 0.45 } } applyLevels() } private func updateDecay() { for i in 0..