Skip to content

Visualization Idle Suppression

log5r edited this page Oct 10, 2026 · 1 revision

可視化・マーキーの抑制と scenePhase の挙動

Issue #31 を PR #55 で修正したときの設計判断と検証方法をまとめます。

設計

  • ホストビューの再評価: TimelineView(paused:) に渡す値は、変化したときだけ代入する PlayerViewModel.isVisualizerIdle にします。フレームごとに変わる audioFrame・fps・EQ 状態は Canvas の中でだけ読みます。旧コードの isPlaying == false && audioFrame.isSilent は短絡評価されるので、フレームごとの再評価は再生中ではなく、一時停止・停止後の減衰(最大約 3 秒)の間に起きていました。
  • 解析の抑制: VisualizationConsumer モディファイアは、audioFrame を描画するビューが表示中であることを登録します。登録しているのはスペクトラム、VU 針、DEBUG の Duo 診断です。consumer がいないとき、または App レベルの scenePhase == .background のときは、SpectrumAnalyzer.setAnalysisEnabled(false) を呼びます。
    • 抑制すると世代が進み、予約済みのチャンク・減衰・未配送のフレームは無効になります。
    • 再開時は無音フレームを 1 回発行して表示を初期化します。
    • 背面で再生中は、再生クロックを 1Hz にします。
  • マーキー: MarqueeTimelineSchedule は、スクロール中だけ 1/60 秒間隔のエントリを返し、保持区間では境界の 1 エントリだけを返します。
  • VU 針: Ballistics.step は経過時間を 1/60 秒以下の等分ステップで積分します。上限は 0.2 秒です。これで 10/30/60fps の応答が一致します。

scenePhase の挙動(App レベル)

App レベルで読む値は全シーンの集約です。いずれかのシーンが .active なら .active になり、.background になるのは全シーンが背面のときだけです。

macOS では、SwiftUI の検証用アプリで次のように確認しました(2026-10-10)。

状態 scenePhase
別アプリの背後で見えているウインドウ .active
ウインドウを最小化 .inactive(onDisappear は呼ばれない)
Cmd-H でアプリを隠す .background
起動直後 一瞬 .background になり、その後 .active

iOS では、ロックやホーム画面への移動で .background になり、コントロールセンターや App スイッチャーの表示中は .inactive になります。iOS 側は文書で確認しただけで、実機では確認していません。.inactive でもアプリは画面に見えていることがあるため、抑制の判定には .background だけを使います。その結果、最小化した macOS ウインドウでは解析が続きます。

未検証

  • Instruments による Path 生成数と body 評価回数の比較
  • iPhone のロック中の Energy Log
  • 実機での復帰表示

Clone this wiki locally