private long timeOfBeat(BeatGrid beatGrid, int beatNumber, DeviceUpdate update) {
        if (beatNumber <= beatGrid.beatCount) {
            return beatGrid.getTimeWithinTrack(beatNumber);
        }
        logger.warn("Received beat number " + beatNumber + " from " + update.getDeviceName() + " " +
                update.getDeviceNumber() + ", but beat grid only goes up to beat " + beatGrid.beatCount +
                ". Packet: " + update);
        if (beatGrid.beatCount < 2) {
            return beatGrid.getTimeWithinTrack(1);
        }
        long lastTime = beatGrid.getTimeWithinTrack(beatGrid.beatCount);
        long lastInterval = lastTime - beatGrid.getTimeWithinTrack(beatGrid.beatCount - 1);
        return lastTime + (lastInterval * (beatNumber - beatGrid.beatCount));
    }
private long timeOfBeat ( BeatGrid beatGrid , int beatNumber , DeviceUpdate update ) { if ( beatNumber <= beatGrid . beatCount ) { return beatGrid . getTimeWithinTrack ( beatNumber ) ; } logger . warn ( "Received beat number " + beatNumber + " from " + update . getDeviceName ( ) + " " + update . getDeviceNumber ( ) + ", but beat grid only goes up to beat " + beatGrid . beatCount + ". Packet: " + update ) ; if ( beatGrid . beatCount < 2 ) { return beatGrid . getTimeWithinTrack ( 1 ) ; } long lastTime = beatGrid . getTimeWithinTrack ( beatGrid . beatCount ) ; long lastInterval = lastTime - beatGrid . getTimeWithinTrack ( beatGrid . beatCount - 1 ) ; return lastTime + ( lastInterval * ( beatNumber - beatGrid . beatCount ) ) ; }
Translates a beat number to a track time, given a beat grid. In almost all cases, simply delegates that task
to the beat grid. However, since players sometimes report beats that are outside the beat grid (especially when
looping tracks that extend for more than a beat's worth of time past the last beat in the beat grid), to avoid
weird exceptions and infinitely-growing track time reports in such situations, we extrapolate an extension to
the beat grid by repeating the interval between the last two beats in the track.

In the completely degenerate case of a track with a single beat (which probably will never occur), we simply
return that beat's time even if you ask for a later one.

@param beatGrid the times at which known beats fall in the track whose playback time we are reporting.

@param beatNumber the number of the beat that a player has just reported reaching, which may be slightly
greater than the actual number of beats in the track.

@param update the device update which caused this calculation to take place, in case we need to log a warning
that the reported beat number falls outside the beat grid.

@return the number of milliseconds into the track at which that beat falls, perhaps extrapolated past the final
recorded beat.