Skip to content

[Metronome] Split local/remote lead time for low-latency conductor monitoring #27

Description

@hakaru

問題

指揮者本人が自分のクリック音を 200ms 遅れで聞くため、演奏感が悪い。

現状

`ConductorService.leadTimeNs = 200_000_000` が local/remote 両方に適用される。

  • Local: 指揮者自身が ictus から 200ms 後にクリックを聞く
  • Remote: ネットワーク保険として 200ms は妥当

指揮者にとって 200ms の遅延は明確に長い(人間の知覚限界 ~30ms を大幅に超える)。

改善方針

Lead time を local/remote で分離:

```swift
static let localLeadTimeNs: UInt64 = 30_000_000 // 30ms 程度
static let remoteLeadTimeNs: UInt64 = 200_000_000 // 200ms
```

  • Local self-monitor は 20-40ms(即時モニタ感覚)
  • Remote broadcast は `base + jitter budget + one-way network budget`

`ConductorService.handleDetectedBeat`:

  • Local 再生用 applyAtNs = syncedNow + localLead
  • Broadcast BeatEvent の applyAtNs = syncedNow + remoteLead

ただし、同じ BeatEvent が 2 つの時刻を持つと受信側が混乱するので、broadcast は remote 用の時刻で送信し、local は別パスで即時再生する実装が必要。

実装案

```swift
private func handleDetectedBeat(_ beat: BeatDetected) async {
let now = mach_absolute_time()
let syncedNow = syncedNowProvider()

let localApplyHost = now + nsToMach(Self.localLeadTimeNs)
let remoteApplyAtNs = syncedNow + Self.remoteLeadTimeNs

// Local immediate trigger
await onLocalBeat(localApplyHost, tickType, beatIndex)

// Remote broadcast
let event = BeatEvent(..., applyAtNs: remoteApplyAtNs)
await onBeatEvent(event)

}
```

重要度

High(UX に直接影響)

関連 issue

#22(hostTime 基準の修正), #25(MainActor 分離)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions