import { deltaTimeTag , MsgType } from "@supercollider/server" ; import { now as _now } from "lodash" ; import { Event } from "../utils/iterators" ; export interface OSCEvent extends Event { msgs : MsgType [ ] ; } interface Memo { i : number ; } interface Next { event : OSCEvent ; memo : Memo ; } type GetNextFn = ( now : number , memo : Memo ) => Next | undefined ; /**
 * Just in time osc scheduler used by scserver middleware
 * to send OSC messages.
 *
 * This is used by the scserver middleware.
 *
 * It is used by calling `.schedLoop(getNext, epoch)`
 */ export default class OSCSched { sendFn : Function ; latency : number ; setTimeout : Function ; clearTimeout : Function ; getNextFn : GetNextFn ; epoch : number ; timerId ? : number ; param { Function } sendFn param { number } latency param { Function } setTimeoutFn param { Function } clearTimeoutFn constructor ( sendFn , latency = 0.05 , setTimeoutFn = setTimeout , clearTimeoutFn = clearTimeout ) { this . sendFn = sendFn ; this . latency = latency ; this . setTimeout = setTimeoutFn ; this . clearTimeout = clearTimeoutFn ; this . getNextFn = ( now , memo ) => undefined ; this . epoch = _now ( ) ; this . timerId = undefined ; } param { Function } getNextFn param { float } epoch schedLoop ( getNextFn , epoch ? ) { this . getNextFn = getNextFn ; if ( ! this . getNextFn ) { throw new Error ( "getNextFn is null" ) ; } if ( epoch ) { this . epoch = epoch ; } else { throw new Error ( `Epoch not set: ${ this . epoch }` ) ; } this . _schedNext ( ) ; } _schedNext ( memo ? , logicalNow ? ) { if ( this . timerId ) { this . clearTimeout ( this . timerId ) ; this . timerId = undefined ; } const now = ( _now ( ) - this . epoch ) / 1000 ; if ( ! logicalNow ) { logicalNow = now ; } const next = this . getNextFn ( logicalNow , memo || { i : 0 } ) ; console . log ( { now , logicalNow , next , epoch : this . epoch , _now : _now ( ) , sub : _now ( ) - this . epoch } ) ; if ( typeof next !== "undefined" ) { const delta = next . event . time - now ; if ( delta <= this . latency ) { if ( delta > 0 ) { this . _send ( next . event ) ; } else { console . warn ( "Event is past due. Skipping." , JSON . stringify ( { delta , now , event : next . event } ) ) ; } this . _schedNext ( next . memo , next . event . time ) ; } else { this . _jitSend ( now , delta , next ) ; } } } param { float } delta param { object } event _jitSend ( now , delta , next ) { this . timerId = this . setTimeout ( ( ) => { this . timerId = undefined ; this . _send ( next . event ) ; this . _schedNext ( next . memo , next . event . time ) ; } , ( delta - this . latency ) * 1000 ) ; } param { object } event _send ( event ) { this . sendFn ( deltaTimeTag ( event . time , this . epoch ) , event . msgs ) ; } }