(define sync-server-receive
(lambda (timestamp address srcip srcport . args)
(cond ((string=? address "/clock/election/q")
;; someone has asked for an election!
;; if we have a higher election-val OR we are allready the master
;; then send a message back, otherwise don't!
(let ((election-val (car args)))
(if (or *master*
(> *election-val* election-val))
(io:osc:send (now) (cons srcip srcport) "/clock/election/r"))))
((string=? address "/clock/election/r")
;; if we receive an election reply
;; then we are definitely NOT the master
;; also don't try for re-election again
;; for AT LEAST 5 seconds!
(set! *toplap-lastmsg* (+ 5. (clock:clock)))
(set! *election-winner* #f))
((string=? address "/clock/sync/q")
;; if someone asks for a clocksync (from any IP and any PORT)
;; and we are the master then send a reply
;; first arg is t1 (from client) we add t2 to reply
(if *master*
(let ((t (split-clock-time (clock:clock))))
(io:osc:send (now) (cons srcip srcport) "/clock/sync/r"
(car args) (cadr args)
(car t) (cdr t)))))
((string=? address "/clock/sync/r")
;; clock syncs come from current master
(let* ((t1 (join-clock-time (car args) (cadr args)))
(t2 (join-clock-time (caddr args) (cadddr args)))
(t3 t2)
(t4 (clock:clock))
(msg-delay (- t4 t1))
(offset (/ (+ (- t2 t1) (- t3 t4)) 2.0)))
(set! *toplap-clock-global-offset* offset)
(set! *masterip* srcip)
(if (not (string=? *masterip* *oldmasterip*))
(begin (ascii-print-color 0 5 9)
(println)
(println 'There 'is 'a 'new 'toplap 'clock 'in 'town! srcip)
(println)
(ascii-print-color 0 7 9)
(set! *master* #f)
(set! *oldmasterip* *masterip*)))
(set! *toplap-lastmsg* (clock:clock))))
((string=? address "/clock/master/q")
;; if current master send reponse
;; srcport need not be same as *toplap-port*
(if *master*
(io:osc:send (now) (cons srcip srcport) "/clock/master/r")))
((string=? address "/clock/master/r")
;; if we get a message it must be from master
;; so we can set the *mastersip* to whatever the srcip is
(set! *mastersip* srcip)) ;; master port must be *toplap-clock-port*
((string=? address "/clock/cycle/set")
;; cycle changes are sent to master only (i.e. not broadcast)
;; to ensure that we don't have the problem where some
;; clients GET the message but the master DOESN'T!
(if *master*
(let ((beat-n (car args))
(beat-d (cadr args))
(cycle (caddr args)))
(*metro* 'set-cycle cycle (/ beat-n beat-d))
;; broadcast new bpm details as cycle/update
(io:osc:send (now) *toplap-sync-broadcast* "/clock/cycle/update"
beat-n beat-d cycle))))
((string=? address "/clock/cycle/update")
(apply io:osc:send (now) *toplap-clock-server* "/clock/cycle/update" args))
((string=? address "/clock/bpm/set")
;; bpm changes are sent to master only (i.e. not broadcast)
;; to ensure that we don't have the problem where some
;; clients GET the message but the master DOESN'T!
(if *master*
(let ((time (join-clock-time (car args) (cadr args)))
(beat-n (caddr args))
(beat-d (cadddr args))
(bpm (car (cddddr args))))
(*metro* 'set-tempo bpm (clock->samples time) (/ beat-n beat-d))
;; broadcast new bpm details as bpm/update
(io:osc:send (now) *toplap-sync-broadcast* "/clock/bpm/update"
(car args) (cadr args) beat-n beat-d bpm))))
((string=? address "/clock/bpm/update")
(apply io:osc:send (now) *toplap-clock-server* "/clock/bpm/update" args))
(else (println 'bad 'osc 'message: address)))))