001 package com.croftsoft.core.animation.clock; 002 003 import com.croftsoft.core.animation.Clock; 004 005 /********************************************************************* 006 * A Clock with higher resolution than the system clock. 007 * 008 * <p> 009 * The system clock on some platforms has a granularity as poor as 010 * 50 or 60 milliseconds. For some applications, such as high 011 * frequency animation, this is insufficient. Film quality animation 012 * of 24 frames per second, for example, has a period of 41.667 013 * milliseconds. This class provides high resolution timing with a 014 * granularity of one nanosecond. 015 * </p> 016 * 017 * <p> 018 * The current implementation samples the system clock each time the 019 * method currentTimeNanos() is called. The period between method 020 * calls is then estimated using round robin windowed averaging. 021 * Assuming the method is called fairly periodically within a loop, 022 * the returned value will be the previous value plus the updated 023 * period estimate whenever the system clock has not been increased. 024 * </p> 025 * 026 * @see 027 * SystemClock 028 * 029 * @version 030 * 2002-12-01 031 * @since 032 * 2002-03-11 033 * @author 034 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 035 *********************************************************************/ 036 037 public final class HiResClock 038 implements Clock 039 ////////////////////////////////////////////////////////////////////// 040 ////////////////////////////////////////////////////////////////////// 041 { 042 043 private final int SAMPLES_LENGTH = 1000; 044 045 // 046 047 private long [ ] samples = new long [ SAMPLES_LENGTH ]; 048 049 private long lastClockTimeNanos; 050 051 private int index; 052 053 private long estimatedTimeNanos; 054 055 private boolean arrayFilled; 056 057 private long estimatedPeriodNanos; 058 059 ////////////////////////////////////////////////////////////////////// 060 ////////////////////////////////////////////////////////////////////// 061 062 public long currentTimeNanos ( ) 063 ////////////////////////////////////////////////////////////////////// 064 { 065 long clockTimeNanos = 1000000L * System.currentTimeMillis ( ); 066 067 // round robin windowed averaging 068 069 if ( arrayFilled ) 070 { 071 estimatedPeriodNanos 072 = ( clockTimeNanos - samples [ index ] ) / SAMPLES_LENGTH; 073 } 074 else 075 { 076 if ( index == 0 ) 077 { 078 estimatedPeriodNanos = 0; 079 } 080 else 081 { 082 estimatedPeriodNanos 083 = ( clockTimeNanos - samples [ 0 ] ) / index; 084 } 085 086 if ( index == SAMPLES_LENGTH - 1 ) 087 { 088 arrayFilled = true; 089 } 090 } 091 092 if ( ( estimatedPeriodNanos > 100000000L ) 093 || ( clockTimeNanos > lastClockTimeNanos + 100000000L ) ) 094 { 095 estimatedPeriodNanos = 0; 096 097 index = 0; 098 099 arrayFilled = false; 100 } 101 102 samples [ index ] = clockTimeNanos; 103 104 index = ( index + 1 ) % SAMPLES_LENGTH; 105 106 if ( clockTimeNanos > lastClockTimeNanos ) 107 { 108 if ( clockTimeNanos > estimatedTimeNanos ) 109 { 110 estimatedTimeNanos = clockTimeNanos; 111 } 112 } 113 else 114 { 115 estimatedTimeNanos += estimatedPeriodNanos; 116 } 117 118 lastClockTimeNanos = clockTimeNanos; 119 120 /* 121 System.out.print ( clockTimeNanos ); 122 123 System.out.print ( " " ); 124 125 System.out.print ( estimatedPeriodNanos ); 126 127 System.out.print ( " " ); 128 129 System.out.println ( estimatedTimeNanos ); 130 */ 131 132 return estimatedTimeNanos; 133 } 134 135 ////////////////////////////////////////////////////////////////////// 136 ////////////////////////////////////////////////////////////////////// 137 }