Submit
Browse
Anonymous
Login
RSS
SuperCollider Code
Fork Code: Clock Difference
name
code content
/* In 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. These classes must be compiled in the usual way before use. Beware, the following contains overrides to other core classes, so please check the full document before using. // nonprivate@cylob.com - 5 March 2007 // HOW TO USE: // execute these one by one on both machines x = C2_ClockDifference.new; x.setup; // then enter i.p. of remote machine, within a second or so you'll get the result // ... this is important, it is not an instant process! y = "192.168.2.21"; // the i.p. to check out x.calcClockDifference(y); // the results get stored in an identity dictionary (called id) for each i.p. investigated // if nothing is received back then nothing gets added to the dictionary x.id.postln; // after the result has been returned, you can do this: (remember to turn the i.p. into a symbol to do so) x.id.at(y.asSymbol).postln; */ C2_ClockDifference { var listener, sender; var remoteAddr, masterAddr; var <id; // Listener is LocalClient // Sender is Client // function is ClientFunc calcClockDifference { arg remoteIP; if( NetAddr.testAddr(remoteIP) == true, { remoteAddr = NetAddr(remoteIP, 57120); // send to the remoteAddr sender = Client(\clockDiffSender, remoteAddr); sender.send(\sendClockDiffMsg, Process.elapsedTime, NetAddr.myIP); }, { ["clock difference - IP is not accessable"].postln; } ); } stopListener { ["C2 clock difference ... listener has been stopped"].postln; listener.stop; } setup { id = IdentityDictionary.new; listener = LocalClient.default; listener.start; // this stuff gets executed on the remote server // it's here because another computer might interrogate this one as the remote server ClientFunc( \sendClockDiffMsg, { arg inProcessTimeSync, sendToIP; var time, getAccurateTime, whenDate, whenProcess, thisProcessTimeSync, sender; ["clock difference ... instruction has been received and will be sent back to IP " ++ sendToIP.asString].postln; sender = Client(\clockDiffReturn, NetAddr(sendToIP.asString, 57120)); thisProcessTimeSync = Process.elapsedTime; getAccurateTime = Routine({ var flag = 0, start; start = Date.localtime.second; while( {flag == 0}, { if (start != Date.localtime.second, { flag = 1; whenDate = Date.localtime; whenProcess = Process.elapsedTime; sender.send(\returnClockDiffResult, inProcessTimeSync, thisProcessTimeSync, whenProcess, whenDate.hour, whenDate.minute, whenDate.second, NetAddr.myIP); } ); 0.00001.wait; } ); }); SystemClock.play(getAccurateTime); } ); // this stuff gets executed here, it is triggered by the remote server ClientFunc( \returnClockDiffResult, { arg processTimeSyncHere, processTimeSyncThere, inProcessTime, inHour, inMinute, inSecond, receivedFromIP; var time, getAccurateTime, whenDate, whenProcess, thereAll, hereAll, serverDelay; if(receivedFromIP.asString == remoteAddr.hostname.asString, { thereAll = [inHour, inMinute, inSecond].deepCopy; getAccurateTime = Routine({ var flag = 0, start; start = Date.localtime.second; while( {flag == 0}, { if (start != Date.localtime.second, { flag = 1; whenDate = Date.localtime; whenProcess = Process.elapsedTime; hereAll = [whenDate.hour, whenDate.minute, whenDate.second]; serverDelay = C2_DateMaths.workOutSchedDelay( inProcessTime, thereAll, processTimeSyncThere, whenProcess, hereAll, processTimeSyncHere ); // cut it some slack serverDelay = serverDelay - 0.001; } ); 0.00001.wait; } ); ["C2_ClockDifference: server delay has been calculated: it is " ++ serverDelay.asString].postln; id.put(receivedFromIP.asSymbol, serverDelay); }); SystemClock.play(getAccurateTime); }, { ["C2_ClockDifference: server delay has NOT been calculated ... received result from unexpected IP"].postln; } ); } ); } } C2_DateMaths { *addSeconds { arg additionValueInSeconds, hms; var temp, leftoverSeconds; var hour, minute, second; hour = hms.at(0); minute = hms.at(1); second = hms.at(2); // hours temp = additionValueInSeconds.div(3600); hour = hour + temp; if (hour < 0, {hour = hour + 24}); if (hour > 23, {hour = hour - 24}); additionValueInSeconds = additionValueInSeconds - (temp * 3600); // minutes temp = additionValueInSeconds.div(60); minute = minute + temp; if (minute < 0, { minute = minute + 60; hour = hour - 1; if (hour < 0, {hour = hour + 24}); } ); if (minute > 59, { minute = minute - 60; hour = hour + 1; if (hour > 23, {hour = hour - 24}); } ); additionValueInSeconds = additionValueInSeconds - (temp * 60); // seconds temp = additionValueInSeconds.div(1); second = second + temp; if (second < 0, { second = second + 60; minute = minute - 1; if (minute < 0, { minute = minute + 60; hour = hour - 1; if (hour < 0, {hour = hour + 24}); } ); } ); if (second > 59, { second = second - 60; minute = minute + 1; if (minute > 59, { minute = minute - 60; hour = hour + 1; if (hour > 23, {hour = hour - 24}); } ); } ); additionValueInSeconds = additionValueInSeconds - temp; leftoverSeconds = additionValueInSeconds; ^[hour, minute, second + leftoverSeconds] } *subtractHmsOutputSeconds { arg hms1, hms2; var outHours, outMinutes, outSeconds; outHours = hms1.at(0) - hms2.at(0); outMinutes = hms1.at(1) - hms2.at(1); outSeconds = hms1.at(2) - hms2.at(2); outSeconds = (outHours * 3600) + (outMinutes * 60) + outSeconds; ^outSeconds } *workOutSchedDelay { arg that_ptDated, that_date, that_ptArb, this_ptDated, this_date, this_ptArb; var that_dateArb, this_dateArb; var x, schedDelay; x = that_ptDated - that_ptArb; that_dateArb = C2_DateMaths.addSeconds(x.neg, that_date); x = this_ptDated - this_ptArb; this_dateArb = C2_DateMaths.addSeconds(x.neg, this_date); schedDelay = C2_DateMaths.subtractHmsOutputSeconds(that_dateArb, this_dateArb); ^schedDelay } } // INCLUDING OVERRIDES ALSO USEFUL FOR OTHER THINGS // bits and pieces adapted and / or stolen from things posted to sc users list + NetAddr { *new { arg hostname, port=0; var addr; addr = if (hostname.notNil, { try { hostname.gethostbyname } { "*** CMS_Overrides: NetAddr ***".postln; ("server " ++ hostname ++ " has not been found, so i.p. will be set to 0.0.0.0").postln; "******************************".postln; hostname = "0.0.0.0"; hostname.gethostbyname } }, { 0 } ); ^super.newCopyArgs(addr, port, hostname); } *testAddr { arg addr; var result = true; try { addr.gethostbyname } { result = false } ^result; } *myIP { var j, k, res; res = Pipe.findValuesForKey("ifconfig", "inet"); ^res !? { res = res.reject(_ == "127.0.0.1"); // remove loopback device ip if(res.size > 1) { warn("the first of those devices were chosen: " ++ res) }; res[0] }; } } + Pipe { *do { arg commandLine, func; var line, pipe = this.new(commandLine, "r"), i=0; { line = pipe.getLine; while { line.notNil } { func.value(line, i); i = i + 1; line = pipe.getLine; } }.protect { pipe.close }; } *findValuesForKey { arg commandLine, key, delimiter=$ ; var j, k, indices, res, keySize; key = key ++ delimiter; keySize = key.size; Pipe.do(commandLine, { |l| indices = l.findAll(key); indices !? { indices.do { |j| j = j + keySize; while { l[j] == delimiter } { j = j + 1 }; k = l.find(delimiter.asString, offset:j) ?? { l.size } - 1; res = res.add(l[j..k]) }; }; }); ^res } }
code description
Migration from the old SourceForge wiki.
use markdown for formating
category tags
comma separated, i.g. "wild, siren" (do not enter default SC class names, please)
ancestor(s)
comma separated identificators, i.g. "1-C,1-1,1-4M,1-x"
Private?
the code will be accessible by direct url and not visible in public activity
signup to submit public code without captcha
comment of change