{
   "labels" : [
      "synchronization",
      "clock",
      "timing"
   ],
   "id" : "1-56Y",
   "is_private" : null,
   "code" : "/*\r\n\r\nIn order to synchronise synthesis events sent to servers running on two different machines, it is necessary to know the difference between their two clocks and compensate for this in the time argument of sendMsg or sendBundle. Here is one method of finding this difference.\r\n\r\nThese classes must be compiled in the usual way before use.\r\n\r\nBeware, the following contains overrides to other core classes, so please check the full document before using.\r\n\r\n// nonprivate@cylob.com - 5 March 2007\r\n\r\n// HOW TO USE:\r\n// execute these one by one on both machines\r\n\r\n\tx = C2_ClockDifference.new;\r\n\tx.setup;\r\n\r\n// then enter i.p. of remote machine, within a second or so you'll get the result\r\n// ... this is important, it is not an instant process!\r\n\r\n\ty = \"192.168.2.21\";\t\t// the i.p. to check out\r\n\tx.calcClockDifference(y);\r\n\r\n// the results get stored in an identity dictionary (called id) for each i.p. investigated\r\n// if nothing is received back then nothing gets added to the dictionary\r\n\r\n\tx.id.postln;\r\n\r\n// after the result has been returned, you can do this: (remember to turn the i.p. into a symbol to do so)\r\n\r\n\tx.id.at(y.asSymbol).postln;\r\n\r\n*/\r\n\r\nC2_ClockDifference {\r\n\r\n\tvar listener, sender;\r\n\tvar remoteAddr, masterAddr; \r\n\tvar <id;\r\n\t\r\n// Listener is LocalClient\r\n// Sender is Client\r\n// function is ClientFunc\r\n\t\r\n\tcalcClockDifference {\r\n\t\r\n\t\targ remoteIP;\r\n\t\t\r\n\t\tif( NetAddr.testAddr(remoteIP) == true,\r\n\t\t\t{\r\n\t\t\tremoteAddr = NetAddr(remoteIP, 57120);\r\n\t\t\t// send to the remoteAddr\r\n\t\t\tsender = Client(\\clockDiffSender, remoteAddr);\r\n\t\t\tsender.send(\\sendClockDiffMsg, Process.elapsedTime, NetAddr.myIP);\r\n\t\t\t},\r\n\t\t\t{\r\n\t\t\t[\"clock difference - IP is not accessable\"].postln;\r\n\t\t\t}\r\n\t\t);\r\n\t\r\n\t\r\n\t}\r\n\t\r\n\tstopListener {\r\n\t\r\n\t\t[\"C2 clock difference ... listener has been stopped\"].postln;\r\n\t \tlistener.stop;\r\n\t \r\n\t }\r\n\r\n\r\n\tsetup {\r\n\t\r\n\t\tid = IdentityDictionary.new;\r\n\t\r\n\t\tlistener = LocalClient.default;\r\n\t\tlistener.start;\r\n\t\r\n\t\r\n\t\t// this stuff gets executed on the remote server\r\n\t\t// it's here because another computer might interrogate this one as the remote server\r\n\t\tClientFunc(\r\n\t\t\t\\sendClockDiffMsg,\r\n\t\t\t{\r\n\t\t\targ inProcessTimeSync, sendToIP;\r\n\t\t\tvar time, getAccurateTime, whenDate, whenProcess, thisProcessTimeSync, sender;\r\n\t\t\t\t[\"clock difference ... instruction has been received and will be sent back to IP \" ++ sendToIP.asString].postln;\r\n\t\t\t\tsender = Client(\\clockDiffReturn, NetAddr(sendToIP.asString, 57120));\r\n\t\t\t\t\r\n\t\t\t\tthisProcessTimeSync = Process.elapsedTime;\r\n\t\t\t\tgetAccurateTime = Routine({\r\n\t\t\t\t\tvar flag = 0, start;\r\n\t\t\t\t\tstart = Date.localtime.second;\r\n\t\t\t\t\twhile(\r\n\t\t\t\t\t\t{flag == 0},\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\tif (start != Date.localtime.second,\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tflag = 1;\r\n\t\t\t\t\t\t\twhenDate = Date.localtime;\r\n\t\t\t\t\t\t\twhenProcess = Process.elapsedTime;\r\n\t\t\t\t\t\t\tsender.send(\\returnClockDiffResult, inProcessTimeSync, thisProcessTimeSync, \r\n\t\t\t\t\t\t\twhenProcess, whenDate.hour, whenDate.minute, whenDate.second, NetAddr.myIP);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t\t0.00001.wait;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t);\r\n\t\t\t\t\t\r\n\t\t\t\t});\r\n\t\t\t\t\r\n\t\t\t\tSystemClock.play(getAccurateTime);\r\n\r\n\t\t\t\r\n\t\t\t}\r\n\t\t);\r\n\t\t\r\n\t\t// this stuff gets executed here, it is triggered by the remote server\r\n\t\tClientFunc(\r\n\t\t\t\\returnClockDiffResult,\r\n\t\t\t{\r\n\t\t\targ processTimeSyncHere, processTimeSyncThere, inProcessTime, inHour, inMinute, inSecond, receivedFromIP;\r\n\t\t\tvar time, getAccurateTime, whenDate, whenProcess, thereAll, hereAll, serverDelay;\r\n\t\t\r\n\t\t\tif(receivedFromIP.asString == remoteAddr.hostname.asString,\r\n\t\t\t\t{\r\n\t\t\t\tthereAll = [inHour, inMinute, inSecond].deepCopy;\r\n\t\t\t\tgetAccurateTime = Routine({\r\n\t\t\t\t\tvar flag = 0, start;\r\n\t\t\t\t\tstart = Date.localtime.second;\r\n\t\t\t\t\twhile(\r\n\t\t\t\t\t\t{flag == 0},\r\n\t\t\t\t\t\t{\r\n\t\t\t\t\t\tif (start != Date.localtime.second,\r\n\t\t\t\t\t\t\t{\r\n\t\t\t\t\t\t\tflag = 1;\r\n\t\t\t\t\t\t\twhenDate = Date.localtime;\r\n\t\t\t\t\t\t\twhenProcess = Process.elapsedTime;\r\n\t\t\t\t\t\t\thereAll = [whenDate.hour, whenDate.minute, whenDate.second];\r\n\t\r\n\t\t\t\t\t\t\tserverDelay = C2_DateMaths.workOutSchedDelay(\r\n\t\t\t\t\t\t\t\tinProcessTime, thereAll, processTimeSyncThere, \r\n\t\t\t\t\t\t\t\twhenProcess, hereAll, processTimeSyncHere\r\n\t\t\t\t\t\t\t);\r\n\t\r\n\t\t\t\t\t\t\t// cut it some slack\r\n\t\t\t\t\t\t\tserverDelay = serverDelay - 0.001;\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t\t0.00001.wait;\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t);\r\n\t\t\t\t\r\n\t\t\t\t[\"C2_ClockDifference: server delay has been calculated: it is \" ++ serverDelay.asString].postln;\r\n\t\t\t\tid.put(receivedFromIP.asSymbol, serverDelay);\r\n\t\t\t\t});\r\n\t\t\t\tSystemClock.play(getAccurateTime);\r\n\t\t\t\t\r\n\t\t\t\t},\r\n\t\t\t\t{\r\n\t\t\t\t[\"C2_ClockDifference: server delay has NOT been calculated ... received result from unexpected IP\"].postln;\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t\t\r\n\t\t\t}\r\n\t\t);\r\n\t\r\n\t}\r\n\r\n\r\n}\r\n\r\n\r\n\r\nC2_DateMaths {\r\n\r\n\r\n\r\n\r\n\t*addSeconds {\r\n\t\r\n\t\targ additionValueInSeconds, hms;\r\n\t\tvar temp, leftoverSeconds;\r\n\t\tvar hour, minute, second;\r\n\t\t\r\n\t\thour = hms.at(0);\r\n\t\tminute = hms.at(1);\r\n\t\tsecond = hms.at(2);\r\n\t// hours\t\r\n\t\ttemp = additionValueInSeconds.div(3600);\r\n\t\thour = hour + temp;\r\n\t\tif (hour < 0, {hour = hour + 24});\r\n\t\tif (hour > 23, {hour = hour - 24});\r\n\t\t\r\n\t\tadditionValueInSeconds = additionValueInSeconds - (temp * 3600);\r\n\t\r\n\t// minutes\t\r\n\t\ttemp = additionValueInSeconds.div(60);\r\n\t\tminute = minute + temp;\r\n\t\tif (minute < 0, \r\n\t\t\t{\r\n\t\t\tminute = minute + 60; hour = hour - 1;\r\n\t\t\tif (hour < 0, {hour = hour + 24});\r\n\t\t\t}\r\n\t\t);\r\n\t\tif (minute > 59, \r\n\t\t\t{\r\n\t\t\tminute = minute - 60; hour = hour + 1;\r\n\t\t\tif (hour > 23, {hour = hour - 24});\r\n\t\t\t}\r\n\t\t);\r\n\t\t\r\n\t\tadditionValueInSeconds = additionValueInSeconds - (temp * 60);\t\t\r\n\t// seconds\t\r\n\t\ttemp = additionValueInSeconds.div(1);\r\n\t\tsecond = second + temp;\r\n\t\t\r\n\t\tif (second < 0, \r\n\t\t\t{\r\n\t\t\tsecond = second + 60; minute = minute - 1;\r\n\t\t\tif (minute < 0, \r\n\t\t\t\t{\r\n\t\t\t\tminute = minute + 60; hour = hour - 1;\r\n\t\t\t\tif (hour < 0, {hour = hour + 24});\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t\t\r\n\t\t\t}\r\n\t\t);\r\n\t\t\r\n\t\tif (second > 59, \r\n\t\t\t{\r\n\t\t\tsecond = second - 60; minute = minute + 1;\r\n\t\t\tif (minute > 59, \r\n\t\t\t\t{\r\n\t\t\t\tminute = minute - 60; hour = hour + 1;\r\n\t\t\t\tif (hour > 23, {hour = hour - 24});\r\n\t\t\t\t}\r\n\t\t\t);\r\n\t\t\t}\r\n\t\t);\r\n\t\t\r\n\t\tadditionValueInSeconds = additionValueInSeconds - temp;\r\n\t\tleftoverSeconds = additionValueInSeconds;\r\n\t\t\t\r\n\t\t^[hour, minute, second + leftoverSeconds]\r\n\t\r\n\t\r\n\t}\r\n\t\r\n\t*subtractHmsOutputSeconds {\r\n\t\r\n\t\targ hms1, hms2;\r\n\t\tvar outHours, outMinutes, outSeconds;\r\n\t\t\r\n\t\toutHours = hms1.at(0) - hms2.at(0);\r\n\t\toutMinutes = hms1.at(1) - hms2.at(1);\r\n\t\toutSeconds = hms1.at(2) - hms2.at(2);\r\n\t\t\r\n\t\toutSeconds = (outHours * 3600) + (outMinutes * 60) + outSeconds;\r\n\t\t\r\n\t\t\r\n\t\t^outSeconds\r\n\r\n\t}\t\r\n\t\r\n\t*workOutSchedDelay {\r\n\t\r\n\t\targ that_ptDated, that_date, that_ptArb, this_ptDated, this_date, this_ptArb;\r\n\t\tvar that_dateArb, this_dateArb;\r\n\t\tvar x, schedDelay;\r\n\t\t\r\n\t\tx = that_ptDated - that_ptArb;\r\n\t\tthat_dateArb = C2_DateMaths.addSeconds(x.neg, that_date);\r\n\t\t\r\n\t\tx = this_ptDated - this_ptArb;\r\n\t\tthis_dateArb = C2_DateMaths.addSeconds(x.neg, this_date);\r\n\t\t\r\n\t\t\r\n\t\tschedDelay = C2_DateMaths.subtractHmsOutputSeconds(that_dateArb, this_dateArb);\r\n\r\n\t\t^schedDelay\r\n\t}\t\r\n\t\r\n\t\r\n}\r\n\r\n// INCLUDING OVERRIDES ALSO USEFUL FOR OTHER THINGS\r\n// bits and pieces adapted and / or stolen from things posted to sc users list\r\n\r\n+ NetAddr {\r\n\r\n\t*new { arg hostname, port=0;\r\n\t\tvar addr;\r\n\t\taddr = \r\n\t\tif (hostname.notNil,\r\n\t\t\t{ \r\n\t\t\t\ttry \r\n\t\t\t\t{ hostname.gethostbyname } \r\n\t\t\t\t{ \r\n\t\t\t\t\"*** CMS_Overrides: NetAddr ***\".postln;\r\n\t\t\t\t(\"server \" ++ hostname ++ \" has not been found, so i.p. will be set to 0.0.0.0\").postln;\r\n\t\t\t\t\"******************************\".postln;\r\n\t\t\t\thostname = \"0.0.0.0\"; \r\n\t\t\t\thostname.gethostbyname \r\n\t\t\t\t}\r\n\t\t\t},\r\n\t\t\t{ \r\n\t\t\t0 \r\n\t\t\t}\r\n\t\t);\r\n\t\t^super.newCopyArgs(addr, port, hostname);\r\n\t}\r\n\t\r\n\t*testAddr {\r\n\t\r\n\t\targ addr;\r\n\t\tvar result = true;\r\n\t\ttry { addr.gethostbyname } { result = false }\r\n\t\t^result;\r\n\t\r\n\t}\r\n\r\n\t*myIP {\r\n\t\tvar j, k, res;\r\n\t\tres = Pipe.findValuesForKey(\"ifconfig\", \"inet\"); \r\n\t\t^res !? {\r\n\t\t\tres = res.reject(_ == \"127.0.0.1\"); // remove loopback device ip\r\n\t\t\tif(res.size > 1) { warn(\"the first of those devices were chosen: \" ++ res) };\r\n\t\t\tres[0]\r\n\t\t};\r\n\t}\r\n\r\n}\r\n\r\n\r\n\r\n+ Pipe {\r\n\t*do { arg commandLine, func;\r\n\t\tvar line, pipe = this.new(commandLine, \"r\"), i=0;\r\n\t\t{\r\n\t\t\tline = pipe.getLine;\r\n\t\t\twhile { line.notNil } {\r\n\t\t\t\tfunc.value(line, i);\r\n\t\t\t\ti = i + 1;\r\n\t\t\t\tline = pipe.getLine;\r\n\t\t\t}\r\n\t\t}.protect { pipe.close };\r\n\r\n\t}\r\n\t*findValuesForKey { arg commandLine, key, delimiter=$ ;\r\n\t\tvar j, k, indices, res, keySize;\r\n\t\tkey = key ++ delimiter;\r\n\t\tkeySize = key.size;\r\n\t\tPipe.do(commandLine, { |l|\r\n\t\t\tindices = l.findAll(key);\r\n\t\t\tindices !? {\r\n\t\t\t\tindices.do { |j|\r\n\t\t\t\t\tj = j + keySize;\r\n\t\t\t\t\twhile { l[j] == delimiter } { j = j + 1 };\r\n\t\t\t\t\tk = l.find(delimiter.asString, offset:j) ?? { l.size } - 1;\r\n\t\t\t\t\tres = res.add(l[j..k])\r\n\t\t\t\t};\r\n\t\t\t};\r\n\t\t});\r\n\t\t^res\r\n\t}\r\n\r\n}",
   "author" : "codepool",
   "name" : "Clock Difference",
   "ancestor_list" : [],
   "description" : "Migration from the old SourceForge wiki."
}
