1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-26 09:29:45 +00:00

Put sufficiently much of PCMTrack into place to get to a stored list of segments, having determined a common clock rate between them and therefore a complete track length.

This commit is contained in:
Thomas Harte 2016-07-10 16:10:05 -04:00
parent 4ae9f5ad5d
commit f9510c1b67
2 changed files with 104 additions and 2 deletions

View File

@ -80,8 +80,8 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
track_length |= (uint16_t)fgetc(_file) << 8;
// grab the byte contents of this track
uint8_t track_contents[track_length];
fread(track_contents, 1, track_length, _file);
std::unique_ptr<uint8_t> track_contents(new uint8_t[track_length]);
fread(track_contents.get(), 1, track_length, _file);
// seek to this track's entry in the speed zone table
fseek(_file, (long)((position * 4) + 0x15c), SEEK_SET);
@ -104,10 +104,83 @@ std::shared_ptr<Track> G64::get_track_at_position(unsigned int position)
// read the speed zone bytes
uint8_t speed_zone_contents[speed_zone_length];
fread(speed_zone_contents, 1, speed_zone_length, _file);
// TODO: divide into individual PCMSegments (per byte, if necessary), shove into a PCMTrack
}
else
{
PCMSegment segment;
segment.duration.length = track_length * 8;
segment.duration.clock_rate = track_length * 8;
segment.data = std::move(track_contents);
resulting_track.reset(new PCMTrack(std::move(segment)));
}
return resulting_track;
}
#pragma mark - PCMTrack
unsigned int greatest_common_divisor(unsigned int a, unsigned int b)
{
if(a < b)
{
unsigned int swap = b;
b = a;
a = swap;
}
while(1) {
if(!a) return b;
if(!b) return a;
unsigned int remainder = a%b;
a = b;
b = remainder;
}
}
unsigned int least_common_multiple(unsigned int a, unsigned int b)
{
unsigned int gcd = greatest_common_divisor(a, b);
return (a*b) / gcd;
}
PCMTrack::PCMTrack(std::vector<PCMSegment> segments)
{
_segments = std::move(segments);
fix_length();
}
PCMTrack::PCMTrack(PCMSegment segment)
{
_segments.push_back(std::move(segment));
fix_length();
}
PCMTrack::Event PCMTrack::get_next_event()
{
PCMTrack::Event new_event;
return new_event;
}
void PCMTrack::fix_length()
{
// find the least common multiple of all segment clock rates
_track_clock_rate = _segments[0].duration.clock_rate;
for(size_t c = 1; c < _segments.size(); c++)
{
_track_clock_rate = least_common_multiple(_track_clock_rate, _segments[c].duration.clock_rate);
}
// therby determine the total length, storing it to next_event as the divisor
_next_event.length.clock_rate = 0;
for(size_t c = 0; c < _segments.size(); c++)
{
unsigned int multiplier = _track_clock_rate / _segments[c].duration.clock_rate;
_next_event.length.clock_rate += _segments[c].duration.length * multiplier;
}
_segment_pointer = _bit_pointer = 0;
}

View File

@ -10,10 +10,39 @@
#define G64_hpp
#include "../Disk.hpp"
#include <vector>
namespace Storage {
struct PCMSegment {
Time duration;
std::unique_ptr<uint8_t> data;
};
class PCMTrack: public Track {
public:
PCMTrack(std::vector<PCMSegment> segments);
PCMTrack(PCMSegment segment);
virtual Event get_next_event();
private:
// storage for the segments that describe this track
std::vector<PCMSegment> _segments;
// a helper to determine the overall track clock rate and it's length
void fix_length();
// the event perpetually returned; impliedly contains the length of the entire track
// as its clock rate, per the need for everything on a Track to sum to a length of 1
PCMTrack::Event _next_event;
// contains the master clock rate
unsigned int _track_clock_rate;
// a pointer to the first bit to consider as the next event
size_t _segment_pointer;
size_t _bit_pointer;
};
class G64: public Disk {