This commit is contained in:
Dallas Groot 2026-04-05 09:02:56 -07:00
parent 920eab741d
commit bbb7faf488
2 changed files with 11 additions and 6 deletions

View file

@ -725,8 +725,10 @@ class AudioPlayer: NSObject, ObservableObject {
#if os(iOS)
stopOfflineVisTimer()
stopLevelTimer()
// Zero out levels immediately so the wave decays cleanly via viscosity
setLevels(Array(repeating: 0, count: 30))
// DO NOT zero _audioLevels here. The Canvas reads zeros when isPlaying=false,
// so the wave decays visually via viscosity smoothing regardless.
// Preserving _audioLevels means on resume the Canvas immediately has real data
// the wave reacts on the very first frame instead of waiting for the timer's first tick.
internalLevels = Array(repeating: 0, count: 30)
#endif
updateNowPlayingInfo()

View file

@ -203,12 +203,15 @@ struct MitsuhaVisualizerView: View {
var body: some View {
Group {
if settings.enabled {
// driver.tick is @Published increments every display frame via CADisplayLink.
// SwiftUI re-evaluates this body each tick, which re-executes the Canvas
// drawing closure. No TimelineView, no .animation schedule dependencies.
let _ = driver.tick
// Reading driver.tick as a local binding forces SwiftUI to register
// a real @Published dependency. The let _ = pattern can be elided by
// the compiler in ViewBuilder context; assigning to a named local is not.
let currentTick = driver.tick
Canvas { context, size in
// Reference currentTick so the Canvas closure captures it
// a new value each frame guarantees SwiftUI re-executes the drawing closure.
_ = currentTick
let now = CACurrentMediaTime()
let rawLevels: [Float] = isPlaying
? (previewLevels ?? AudioPlayer.shared.currentLevels())