ADR 0001: 波形の変化を見せるため、表示の横位置を追跡する
- 状態: 採用
- 確認: userがRust GUIの動作を確認し「合格」。診断ツールの撤去も承認。
何の話か
オシロスコープでは、今鳴っている音の波形を違和感なく見たい。 音色による形の変化を観察する際、同じような波形の横移動やnote切替時のジャンプが邪魔になる。 形が変わることと、時間軸の平行移動で合うことは区別する。
保存WAVの連続4周期をHTMLで表示し、人間が確認した。 同じnote内の表示は良好で、次noteを横移動すると切替時のジャンプ感が減った。 正側の山頂を目印にした境界合わせと500msの追従を経て、Rust GUIでも合格した。
決定
- 既定は4 cycles / Similarity。名前は従来のUIを引き継ぐが、現方式は相関探索ではなく山頂の位相追跡。
- MIDI noteの公称周波数から4周期のsample数を算出し、連続する完全窓を順に処理する。 note切替の端数は捨て、新noteの最初の完全窓まで直前の表示を保持する。
- 各周期で正側の局所山頂を1つ選ぶ。同じnoteでは前回位相から±0.12周期以内の 最も近い山を追跡し、倍音の高さ逆転で別の山へ飛ぶことを避ける。 共通位相の中央値から±0.12周期を超える候補は除外し、3本以上で位相を有効とする。
- 新noteの最初の窓を直前の補正済み位置へ合わせる。その後は最初の有効な横位置を
目標として、sample時間による指数追従
alpha = 1 - exp(-dt / 0.5)でドリフトを補正する。 目標は有効な参照が続く限りnoteをまたいで保持する。固定するのは横位置であり波形の形ではない。 - 初窓の目印不足ではそのnote全体の補正を開始しない。途中の不足では補正量を保持する。 sample欠落・note不明・設定変更・参照チャンネル変更で参照を初期化する。
- 元sampleは加工せず、波形と任意の赤線を同じ量だけ横移動して描く。 縦方向は従来のL/R共通peakによるnormalizeのみ。赤線は既定OFF、設定は☰内。
- 解析は全完成窓で進め、GUIは最新の完成窓を描く。波形表示中の再描画要求は1/60秒。
- 実装の判断に使った診断CLI、WAV/CSV保存、HTML生成、旧相関追跡試作と専用テストは撤去する。 GUI処理の回帰テストを残す。保存済みの診断データは削除しない。
見送ったもの
| 案 | 理由 |
|---|---|
| 最初の波形の形への固定 | 自然な音色変化まで取り除こうとする。今回の目的は横位置の安定 |
| 前回や複数履歴との相関探索 | 調査用の試作。人間が合格した連続窓・山頂追跡方式を採用 |
| ドリフトの0ms追従 | userは0msと500ms両方の利点を確認し、まず500msを選択 |
| 手動縦倍率 | userは従来のnormalizeだけを希望。固定×4と倍率操作を削除 |
制約
- 現方式は描画の平行移動で、音声窓の開始を取り直すトリガリングではない。端はクリップされる。
- noteから算出する公称周期と実音の周期は一致するとは限らない。多声音・強い倍音・pitch bendなどへの一般的な有効性は未確認。 山頂の変化が位相変化として扱われる可能性があり、目印不足時は無理に別の方式へ切り替えない。
- normalizeはL/R比を保持するが、窓間の振幅の絶対変化は見えない。
- 1/2 cyclesは4周期到着後に先頭1/2周期を表示。8 cyclesは8周期到着後に先頭4周期で解析する。 数値でHTMLと照合した対象は既定4 cycles。8 cyclesの赤線も解析した先頭4周期だけ。
- 60Hzは再描画の要求で、実fpsや全解析窓の表示を保証しない。 note48の4周期窓は48kHzで約30.6msなので、60Hzでも同じ完成窓を再表示する回がある。
- Zero crossは従来の別方式として残す。今回の診断・改善の対象にはしていない。
検証と再発時の入口
撤去前の保存WAVの600窓で、GUI共通処理の元sampleはbit一致し、HTML500msとの補正量の差は 最大2.22e-16周期だった。これに加えてuserの実GUI確認を採否の根拠とした。
回帰テストはscope_boundary_tests.rs、scope_drift_tests.rs、scope_stream_tests.rsと
音声取り込み・worker・normalizeのテストに残す。
再発時は同note中かnote境界か、形の変化か横移動かを分け、山頂の高さ逆転、目印不足、
sample欠落、参照チャンネル切替を確認する。描画の滑らかさは実GUIで測定して判断する。