問題
指揮者本人が自分のクリック音を 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 分離)
問題
指揮者本人が自分のクリック音を 200ms 遅れで聞くため、演奏感が悪い。
現状
`ConductorService.leadTimeNs = 200_000_000` が local/remote 両方に適用される。
指揮者にとって 200ms の遅延は明確に長い(人間の知覚限界 ~30ms を大幅に超える)。
改善方針
Lead time を local/remote で分離:
```swift
static let localLeadTimeNs: UInt64 = 30_000_000 // 30ms 程度
static let remoteLeadTimeNs: UInt64 = 200_000_000 // 200ms
```
`ConductorService.handleDetectedBeat`:
ただし、同じ BeatEvent が 2 つの時刻を持つと受信側が混乱するので、broadcast は remote 用の時刻で送信し、local は別パスで即時再生する実装が必要。
実装案
```swift
private func handleDetectedBeat(_ beat: BeatDetected) async {
let now = mach_absolute_time()
let syncedNow = syncedNowProvider()
}
```
重要度
High(UX に直接影響)
関連 issue
#22(hostTime 基準の修正), #25(MainActor 分離)