2016-12-17 00:20:38 +00:00
|
|
|
//
|
|
|
|
// PCMPatchedTrack.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 15/12/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "PCMPatchedTrack.hpp"
|
|
|
|
|
|
|
|
using namespace Storage::Disk;
|
|
|
|
|
2016-12-17 23:17:22 +00:00
|
|
|
PCMPatchedTrack::PCMPatchedTrack(std::shared_ptr<Track> underlying_track) :
|
2016-12-19 12:42:43 +00:00
|
|
|
underlying_track_(underlying_track)
|
|
|
|
{
|
2016-12-20 12:30:57 +00:00
|
|
|
const Time zero(0);
|
|
|
|
const Time one(1);
|
2016-12-19 12:42:43 +00:00
|
|
|
periods_.emplace_back(zero, one, zero, nullptr);
|
2016-12-20 12:30:57 +00:00
|
|
|
active_period_ = periods_.begin();
|
|
|
|
underlying_track_->seek_to(zero);
|
2016-12-19 12:42:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void PCMPatchedTrack::add_segment(const Time &start_time, const PCMSegment &segment)
|
|
|
|
{
|
|
|
|
event_sources_.emplace_back(segment);
|
|
|
|
|
|
|
|
Time zero(0);
|
2016-12-20 02:46:02 +00:00
|
|
|
Time end_time = start_time + event_sources_.back().get_length();
|
|
|
|
Period insertion_period(start_time, end_time, zero, &event_sources_.back());
|
2016-12-19 12:42:43 +00:00
|
|
|
|
|
|
|
// the new segment may wrap around, so divide it up into track-length parts if required
|
|
|
|
Time one = Time(1);
|
|
|
|
while(insertion_period.end_time > one)
|
|
|
|
{
|
|
|
|
Time next_end_time = insertion_period.end_time - one;
|
|
|
|
insertion_period.end_time = one;
|
|
|
|
insert_period(insertion_period);
|
|
|
|
|
|
|
|
insertion_period.start_time = zero;
|
|
|
|
insertion_period.end_time = next_end_time;
|
|
|
|
}
|
|
|
|
insert_period(insertion_period);
|
2016-12-20 02:46:02 +00:00
|
|
|
|
|
|
|
// the vector may have been resized, potentially invalidating active_period_ even if
|
|
|
|
// the thing it pointed to is still the same thing. So work it out afresh.
|
2016-12-20 12:30:57 +00:00
|
|
|
active_period_ = periods_.begin();
|
|
|
|
while(active_period_->start_time > current_time_) active_period_++;
|
2016-12-19 12:42:43 +00:00
|
|
|
}
|
2016-12-17 21:26:45 +00:00
|
|
|
|
2016-12-19 12:42:43 +00:00
|
|
|
void PCMPatchedTrack::insert_period(const Period &period)
|
2016-12-17 00:20:38 +00:00
|
|
|
{
|
2016-12-19 12:42:43 +00:00
|
|
|
// find the existing period that the new period starts in
|
|
|
|
size_t start_index = 0;
|
|
|
|
while(periods_[start_index].start_time >= period.end_time) start_index++;
|
|
|
|
|
|
|
|
// find the existing period that the new period end in
|
|
|
|
size_t end_index = 0;
|
|
|
|
while(periods_[end_index].end_time < period.end_time) end_index++;
|
|
|
|
|
|
|
|
// perform a division if called for
|
|
|
|
if(start_index == end_index)
|
|
|
|
{
|
|
|
|
Period right_period = periods_[start_index];
|
|
|
|
|
|
|
|
Time adjustment = period.start_time - right_period.start_time;
|
|
|
|
right_period.end_time += adjustment;
|
|
|
|
right_period.segment_start_time += adjustment;
|
|
|
|
|
|
|
|
periods_[start_index].end_time = period.start_time;
|
|
|
|
periods_.insert(periods_.begin() + (int)start_index + 1, period);
|
|
|
|
periods_.insert(periods_.begin() + (int)start_index + 2, right_period);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// perform a left chop on the thing at the start and a right chop on the thing at the end
|
|
|
|
periods_[start_index].end_time = period.start_time;
|
|
|
|
|
|
|
|
Time adjustment = period.start_time - periods_[end_index].start_time;
|
|
|
|
periods_[end_index].end_time += adjustment;
|
|
|
|
periods_[end_index].segment_start_time += adjustment;
|
|
|
|
|
|
|
|
// remove anything in between
|
|
|
|
periods_.erase(periods_.begin() + (int)start_index + 1, periods_.begin() + (int)end_index - 1);
|
|
|
|
|
|
|
|
// insert the new period
|
|
|
|
periods_.insert(periods_.begin() + (int)start_index + 1, period);
|
|
|
|
}
|
2016-12-17 00:20:38 +00:00
|
|
|
}
|
2016-12-17 21:26:45 +00:00
|
|
|
|
|
|
|
Track::Event PCMPatchedTrack::get_next_event()
|
|
|
|
{
|
2016-12-20 12:30:57 +00:00
|
|
|
const Time one(1);
|
|
|
|
const Time zero(0);
|
|
|
|
Time extra_time(0);
|
|
|
|
Time period_error(0);
|
|
|
|
|
2016-12-20 02:46:02 +00:00
|
|
|
while(1)
|
|
|
|
{
|
2016-12-20 12:30:57 +00:00
|
|
|
// get the next event from the current active period
|
2016-12-20 02:46:02 +00:00
|
|
|
Track::Event event;
|
|
|
|
if(active_period_->event_source) event = active_period_->event_source->get_next_event();
|
|
|
|
else event = underlying_track_->get_next_event();
|
|
|
|
|
2016-12-20 12:30:57 +00:00
|
|
|
// see what time that gets us to. If it's still within the current period, return the found event
|
2016-12-20 02:46:02 +00:00
|
|
|
current_time_ += event.length;
|
2016-12-20 12:30:57 +00:00
|
|
|
if(current_time_ < active_period_->end_time)
|
2016-12-20 02:46:02 +00:00
|
|
|
{
|
2016-12-20 12:30:57 +00:00
|
|
|
event.length += extra_time - period_error;
|
|
|
|
return event;
|
2016-12-20 02:46:02 +00:00
|
|
|
}
|
|
|
|
|
2016-12-20 12:30:57 +00:00
|
|
|
// otherwise move time back to the end of the outgoing period, accumulating the error into
|
|
|
|
// extra_time, and advance the extra period
|
|
|
|
extra_time += (current_time_ - active_period_->end_time);
|
|
|
|
current_time_ = active_period_->end_time;
|
|
|
|
active_period_++;
|
2016-12-17 21:26:45 +00:00
|
|
|
|
2016-12-20 12:30:57 +00:00
|
|
|
// test for having reached the end of the track
|
|
|
|
if(active_period_ == periods_.end())
|
2016-12-20 02:46:02 +00:00
|
|
|
{
|
2016-12-20 12:30:57 +00:00
|
|
|
// if this is the end of the track then jump the active pointer back to the beginning
|
|
|
|
// of the list of periods and reset current_time_ to zero
|
|
|
|
active_period_ = periods_.begin();
|
|
|
|
if(active_period_->event_source) active_period_->event_source->reset();
|
|
|
|
else underlying_track_->seek_to(zero);
|
|
|
|
current_time_ = zero;
|
|
|
|
|
|
|
|
// then return an index hole that is the aggregation of accumulated extra_time away
|
|
|
|
event.type = Storage::Disk::Track::Event::IndexHole;
|
|
|
|
event.length = extra_time;
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// if this is not the end of the track then move to the next period and note how much will need
|
|
|
|
// to be subtracted if an event is found here
|
|
|
|
if(active_period_->event_source) period_error = active_period_->segment_start_time - active_period_->event_source->seek_to(active_period_->segment_start_time);
|
|
|
|
else period_error = underlying_track_->seek_to(current_time_) - current_time_;
|
2016-12-20 02:46:02 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-20 12:30:57 +00:00
|
|
|
}
|
2016-12-20 02:46:02 +00:00
|
|
|
|
2016-12-20 12:30:57 +00:00
|
|
|
Storage::Time PCMPatchedTrack::seek_to(const Time &time_since_index_hole)
|
|
|
|
{
|
|
|
|
// start at the beginning and continue while segments start after the time sought
|
|
|
|
active_period_ = periods_.begin();
|
|
|
|
while(active_period_->start_time > time_since_index_hole) active_period_++;
|
|
|
|
|
|
|
|
// allow whatever storage represents the period found to perform its seek
|
2016-12-20 02:46:02 +00:00
|
|
|
if(active_period_->event_source)
|
2016-12-20 12:30:57 +00:00
|
|
|
return active_period_->event_source->seek_to(time_since_index_hole - active_period_->start_time) + active_period_->start_time;
|
2016-12-20 02:46:02 +00:00
|
|
|
else
|
2016-12-20 12:30:57 +00:00
|
|
|
return underlying_track_->seek_to(time_since_index_hole);
|
2016-12-17 21:26:45 +00:00
|
|
|
}
|