diff --git a/Storage/Disk/Disk.hpp b/Storage/Disk/Disk.hpp index 7aaf98f79..08e3ee607 100644 --- a/Storage/Disk/Disk.hpp +++ b/Storage/Disk/Disk.hpp @@ -37,9 +37,16 @@ class Track { }; /*! - Returns the next event that will be detected during rotation of this disk. + @returns the next event that will be detected during rotation of this disk. */ virtual Event get_next_event() = 0; + + /*! + Jumps to the event latest offset that is less than or equal to the input time. + + @returns the time jumped to. + */ + virtual Time seek_to(Time time_since_index_hole) = 0; }; /*! diff --git a/Storage/Disk/PCMTrack.cpp b/Storage/Disk/PCMTrack.cpp index f909c33a0..fc1d9ebfc 100644 --- a/Storage/Disk/PCMTrack.cpp +++ b/Storage/Disk/PCMTrack.cpp @@ -61,6 +61,45 @@ PCMTrack::Event PCMTrack::get_next_event() return _next_event; } +Time PCMTrack::seek_to(Time time_since_index_hole) +{ + _segment_pointer = 0; + + // pick a common clock rate for counting time on this track and multiply up the time being sought appropriately + Time time_so_far; + time_so_far.clock_rate = NumberTheory::least_common_multiple(_track_clock_rate, time_since_index_hole.clock_rate); + time_since_index_hole.length *= time_so_far.clock_rate / time_since_index_hole.clock_rate; + time_since_index_hole.clock_rate = time_so_far.clock_rate; + + while(_segment_pointer < _segments.size()) + { + // determine how long this segment is in terms of the master clock + unsigned int clock_multiplier = time_so_far.clock_rate / _segments[_segment_pointer].length_of_a_bit.clock_rate; + unsigned int resolution_in_this_segment = _segments[_segment_pointer].length_of_a_bit.length * clock_multiplier; + unsigned int time_in_this_segment = resolution_in_this_segment * _segments[_segment_pointer].number_of_bits; + + // if this segment goes on longer than the time being sought, end here + unsigned int time_remaining = time_since_index_hole.length - time_so_far.length; + if(time_in_this_segment >= time_remaining) + { + // get the amount of time actually to move into this segment + unsigned int time_found = time_remaining - (time_remaining % resolution_in_this_segment); + + // resolve that into the stateful bit count + _bit_pointer = time_remaining / resolution_in_this_segment; + + // update and return the time sought to + time_so_far.length += time_found; + return time_so_far; + } + + // otherwise, accumulate time and keep moving + time_so_far.length += time_in_this_segment; + _segment_pointer++; + } + return time_since_index_hole; +} + void PCMTrack::fix_length() { // find the least common multiple of all segment clock rates diff --git a/Storage/Disk/PCMTrack.hpp b/Storage/Disk/PCMTrack.hpp index f16c0ca7d..99e426281 100644 --- a/Storage/Disk/PCMTrack.hpp +++ b/Storage/Disk/PCMTrack.hpp @@ -47,6 +47,7 @@ class PCMTrack: public Track { // as per @c Track Event get_next_event(); + Time seek_to(Time time_since_index_hole); private: // storage for the segments that describe this track diff --git a/Storage/Storage.hpp b/Storage/Storage.hpp index 5797fba34..74852f5a1 100644 --- a/Storage/Storage.hpp +++ b/Storage/Storage.hpp @@ -19,6 +19,7 @@ namespace Storage { */ struct Time { unsigned int length, clock_rate; + Time() : length(0), clock_rate(1) {} /*! Reduces this @c Time to its simplest form — eliminates all common factors from @c length @@ -32,14 +33,28 @@ struct Time { } /*! - Returns the floating point conversion of this @c Time. This will often be less precise. + @returns the floating point conversion of this @c Time. This will often be less precise. */ inline float get_float() { return (float)length / (float)clock_rate; } + + inline bool operator<(Time &other) + { + return other.clock_rate * length < clock_rate * other.length; + } + + inline Time operator+(Time &other) + { + Time result; + result.clock_rate = NumberTheory::least_common_multiple(clock_rate, other.clock_rate); + result.length = length * (clock_rate / result.clock_rate) + other.length * (other.clock_rate / result.clock_rate); + return result; + } }; + } #endif /* Storage_h */