diff --git a/demo.ts b/demo.ts index 6b68298..b84708a 100644 --- a/demo.ts +++ b/demo.ts @@ -1,13 +1,8 @@ -import { createMetronome } from "./src" -import { sync } from "./src/clock.ts" +import { createMetronome, syncClock } from "./src" -async function doSync() { - const offset = await sync() - document.getElementById('offset')!.innerText = offset.toString() - setTimeout(doSync, 5000) -} - -setTimeout(doSync(), 1000) +setTimeout(async () => { + document.getElementById('offset')!.innerText = (await syncClock()).toString() +}, 1000) const tempoEl = document.getElementById("tempo")! as HTMLInputElement const visualizerEl = document.getElementById("visualizer")! as HTMLInputElement diff --git a/src/clock.ts b/src/clock.ts index 7dcf2e4..2046e63 100644 --- a/src/clock.ts +++ b/src/clock.ts @@ -1,35 +1,42 @@ // The number of milliseconds that this client's clock is offset from the server's clock. -export let offset = 0; -let delay = Infinity; +export let offset = 0 +let latency = Infinity // the NTP algorithm // t0 - client's timestamp of the request packet transmission, // t1 - server's timestamp of the request packet reception, // t2 - server's timestamp of the response packet transmission and // t3 - client's timestamp of the response packet reception. -export function ntp(t0, t1, t2, t3) { +export function ntp(t0: number, t1: number, t2: number, t3: number) { return { - delay: (t3 - t0) - (t2 - t1), + latency: (t3 - t0) - (t2 - t1), offset: ((t1 - t0) + (t2 - t3)) / 2 - }; + } } -export async function sync () { - const t0 = Date.now() - const response = await fetch('https://clock.zone/_/_offset') - const t3 = Date.now() - const { val } = await response.json(); +export async function sync ({ iterations, wait } = { iterations: 5, wait: 1000 }) { + for (let i = 0; i < iterations; i++) { + const t0 = Date.now() + const response = await fetch('https://clock.zone/_/_offset') + const t3 = Date.now() + const { val } = await response.json(); + + const latest = ntp(t0, val, val, t3) - const latest = ntp(t0, val, val, t3) + // Less latency is likely higher accuracy + if(latest.latency < latency) { + offset = latest.offset + latency = latest.latency + } - if(latest.delay < delay) { - offset = latest.offset - delay = latest.delay + if(i < iterations) { + await new Promise(resolve => setTimeout(resolve, wait)) + } } return offset } export function now() { - return Date.now() + offset; + return Date.now() + offset } diff --git a/src/index.ts b/src/index.ts index b91aacc..9b5d07d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,8 @@ import { setInterval, clearInterval } from "./timers" import { now } from "./clock" +export { sync as syncClock } from "./clock" + export interface Beat { note: number time: number