2017-09-27 02:01:32 +00:00
|
|
|
//
|
|
|
|
// TrackSerialiser.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 26/09/2017.
|
2018-05-13 19:19:52 +00:00
|
|
|
// Copyright 2017 Thomas Harte. All rights reserved.
|
2017-09-27 02:01:32 +00:00
|
|
|
//
|
|
|
|
|
|
|
|
#include "TrackSerialiser.hpp"
|
|
|
|
|
2018-05-19 03:03:28 +00:00
|
|
|
#include <memory>
|
|
|
|
|
2017-09-27 02:01:32 +00:00
|
|
|
// TODO: if this is a PCMTrack with only one segment and that segment's bit rate is within tolerance,
|
|
|
|
// just return a copy of that segment.
|
2018-05-19 03:03:28 +00:00
|
|
|
Storage::Disk::PCMSegment Storage::Disk::track_serialisation(const Track &track, Time length_of_a_bit) {
|
2017-09-27 02:01:32 +00:00
|
|
|
unsigned int history_size = 16;
|
2018-05-19 03:03:28 +00:00
|
|
|
std::unique_ptr<Track> track_copy(track.clone());
|
2017-09-27 02:01:32 +00:00
|
|
|
|
2018-07-01 18:41:17 +00:00
|
|
|
// ResultAccumulator exists to append whatever comes out of the PLL to
|
|
|
|
// its PCMSegment.
|
2020-01-12 22:25:21 +00:00
|
|
|
struct ResultAccumulator {
|
2017-09-27 02:01:32 +00:00
|
|
|
PCMSegment result;
|
2020-01-12 22:45:02 +00:00
|
|
|
bool is_recording = false;
|
2017-09-27 02:01:32 +00:00
|
|
|
void digital_phase_locked_loop_output_bit(int value) {
|
2020-01-12 22:45:02 +00:00
|
|
|
if(is_recording) result.data.push_back(!!value);
|
2017-09-27 02:01:32 +00:00
|
|
|
}
|
|
|
|
} result_accumulator;
|
|
|
|
result_accumulator.result.length_of_a_bit = length_of_a_bit;
|
2020-01-12 22:45:02 +00:00
|
|
|
DigitalPhaseLockedLoop<ResultAccumulator> pll(100, result_accumulator);
|
2017-09-27 02:01:32 +00:00
|
|
|
|
2018-07-01 18:41:17 +00:00
|
|
|
// Obtain a length multiplier which is 100 times the reciprocal
|
|
|
|
// of the expected bit length. So a perfect bit length from
|
|
|
|
// the source data will come out as 100 ticks.
|
2017-09-27 02:01:32 +00:00
|
|
|
Time length_multiplier = Time(100*length_of_a_bit.clock_rate, length_of_a_bit.length);
|
|
|
|
length_multiplier.simplify();
|
|
|
|
|
|
|
|
// start at the index hole
|
2018-05-19 03:03:28 +00:00
|
|
|
track_copy->seek_to(Time(0));
|
2017-09-27 02:01:32 +00:00
|
|
|
|
|
|
|
// grab events until the next index hole
|
|
|
|
Time time_error = Time(0);
|
|
|
|
while(true) {
|
2018-05-19 03:03:28 +00:00
|
|
|
Track::Event next_event = track_copy->get_next_event();
|
2017-09-27 02:01:32 +00:00
|
|
|
|
|
|
|
Time extended_length = next_event.length * length_multiplier + time_error;
|
|
|
|
time_error.clock_rate = extended_length.clock_rate;
|
|
|
|
time_error.length = extended_length.length % extended_length.clock_rate;
|
2020-05-10 03:00:39 +00:00
|
|
|
pll.run_for(Cycles(int(extended_length.get<int64_t>())));
|
2019-07-16 20:36:00 +00:00
|
|
|
|
|
|
|
if(next_event.type == Track::Event::IndexHole) break;
|
2017-09-27 02:01:32 +00:00
|
|
|
pll.add_pulse();
|
|
|
|
|
|
|
|
// If the PLL is now sufficiently primed, restart, and start recording bits this time.
|
|
|
|
if(history_size) {
|
|
|
|
history_size--;
|
|
|
|
if(!history_size) {
|
2018-05-19 03:03:28 +00:00
|
|
|
track_copy->seek_to(Time(0));
|
2017-09-27 02:01:32 +00:00
|
|
|
time_error.set_zero();
|
2020-01-12 22:45:02 +00:00
|
|
|
result_accumulator.is_recording = true;
|
2017-09-27 02:01:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return result_accumulator.result;
|
|
|
|
}
|