Files
nenya/src/java/com/threerings/media/timer/CalibratingTimer.java
T
Charlie Groves 5a569a2fa3 Adjust _startStamp by the amount of drift since the previous call to elapsed rather than adjusting the entire elapsed time.
git-svn-id: svn+ssh://src.earth.threerings.net/nenya/trunk@429 ed5b42cb-e716-0410-a449-f6a68f950b19
2008-02-27 19:15:08 +00:00

111 lines
3.7 KiB
Java

package com.threerings.media.timer;
import com.samskivert.Log;
/**
* Calibrates timing values from a subclass' implementation of current against those returned by
* System.currentTimeMillis. If the subclass timer is moving 1.25 times faster or .75 times slower
* than currentTimeMillis, hold it to the values from currentTimeMillis.
*/
public abstract class CalibratingTimer
implements MediaTimer
{
/**
* Initializes this timer. Must be called before the timer is used.
*
* @param milliDivider - value by which current() must be divided to get milliseconds
* @param microDivider - value by which current() must be divided to get microseconds
*/
protected void init (long milliDivider, long microDivider)
{
_milliDivider = milliDivider;
_microDivider = microDivider;
reset();
Log.info("Using " + getClass() + " timer [mfreq=" + _milliDivider + ", ufreq="
+ _microDivider + ", start=" + _startStamp + "].");
}
// documentation inherited from interface
public long getElapsedMicros ()
{
return elapsed() / _microDivider;
}
// documentation inherited from interface
public long getElapsedMillis ()
{
return elapsed() / _milliDivider;
}
// documentation inherited from interface
public void reset ()
{
_startStamp = _priorCurrent = current();
_driftMilliStamp = System.currentTimeMillis();
_driftTimerStamp = current();
_callsSinceCalibration = 0;
}
/** Returns the difference between _startStamp and current() */
protected long elapsed ()
{
if (_callsSinceCalibration++ > 1000) {
calibrate();
}
long current = current();
if (_driftRatio != 1.0) {
long elapsed = current - _priorCurrent;
_startStamp += (elapsed - (elapsed * _driftRatio));
_priorCurrent = current;
}
return current - _startStamp;
}
/** Calculates the drift factor from the time elapsed from the last calibrate call. */
protected void calibrate ()
{
long elapsedTimer = (current() - _driftTimerStamp);
double elapsedMillis = System.currentTimeMillis() - _driftMilliStamp;
double drift = elapsedMillis / (elapsedTimer / _milliDivider);
if (drift > 1.25 || drift < 0.75) {
Log.warning("Calibrating [drift=" + drift + "]");
_driftRatio = drift;
} else if (_driftRatio != 1.0) {
// If we're within bounds now but we weren't before, reset _driftFactor and log it
_driftRatio = 1.0;
Log.warning("Calibrating [drift=" + drift + "]");
}
_driftMilliStamp = System.currentTimeMillis();
_driftTimerStamp = current();
_callsSinceCalibration = 0;
}
/** Return the current value for this timer. */
public abstract long current ();
/** current() value when the timer was started. */
protected long _startStamp;
/** current() value when elapsed was called last. */
protected long _priorCurrent;
/** Amount by which current() should be divided to get milliseconds. */
protected long _milliDivider;
/** Amount by which current() should be divided to get microseconds. */
protected long _microDivider;
/** currentTimeMillis() value from the last time we called calibrate. */
protected long _driftMilliStamp = System.currentTimeMillis();
/** current() value from the last time we called calibrate. */
protected long _driftTimerStamp;
/** Ratio of currentTimeMillis to timer millis. */
protected double _driftRatio = 1.0;
/** Number of calls to elapsed since we've called calibrate. */
protected int _callsSinceCalibration = 0;
}