mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-29 12:50:28 +00:00
Makes an initial removal of PCMPatchedTrack
. Farewell, old friend.
This commit is contained in:
parent
b4be2cd063
commit
abca38a548
@ -165,7 +165,7 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
||||
constexpr HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||
|
||||
/// @returns The number of whole cycles completely covered by this span of half cycles.
|
||||
constexpr Cycles cycles() {
|
||||
constexpr Cycles cycles() const {
|
||||
return Cycles(length_ >> 1);
|
||||
}
|
||||
|
||||
|
@ -43,7 +43,6 @@
|
||||
4B055AA81FAE85EF0060FFFF /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; };
|
||||
4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
|
||||
4B055AAA1FAE85F50060FFFF /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.cpp */; };
|
||||
4B055AAB1FAE85FD0060FFFF /* PCMPatchedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */; };
|
||||
4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
|
||||
4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
||||
4B055AAE1FAE85FD0060FFFF /* TrackSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */; };
|
||||
@ -125,7 +124,6 @@
|
||||
4B0E61071FF34737002A9DBD /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; };
|
||||
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
|
||||
4B0F94FF208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */; };
|
||||
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
|
||||
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
|
||||
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
|
||||
@ -186,7 +184,6 @@
|
||||
4B44EBF51DC987AF00A7820C /* AllSuiteA.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */; };
|
||||
4B44EBF71DC9883B00A7820C /* 6502_functional_test.bin in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */; };
|
||||
4B44EBF91DC9898E00A7820C /* BCDTEST_beeb in Resources */ = {isa = PBXBuildFile; fileRef = 4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */; };
|
||||
4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */; };
|
||||
4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
|
||||
4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
||||
4B4518841F75E91A00926311 /* UnformattedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518771F75E91800926311 /* UnformattedTrack.cpp */; };
|
||||
@ -720,7 +717,6 @@
|
||||
4B0F94FC208C1A1600FE41D9 /* NIB.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NIB.cpp; sourceTree = "<group>"; };
|
||||
4B0F94FD208C1A1600FE41D9 /* NIB.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NIB.hpp; sourceTree = "<group>"; };
|
||||
4B0F9500208C42A300FE41D9 /* Target.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Target.hpp; path = AppleII/Target.hpp; sourceTree = "<group>"; };
|
||||
4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMPatchedTrackTests.mm; sourceTree = "<group>"; };
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PCMSegmentEventSourceTests.mm; sourceTree = "<group>"; };
|
||||
4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = Keyboard.cpp; path = MSX/Keyboard.cpp; sourceTree = "<group>"; };
|
||||
4B12C0EC1FCFA98D005BFD93 /* Keyboard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = Keyboard.hpp; path = MSX/Keyboard.hpp; sourceTree = "<group>"; };
|
||||
@ -827,8 +823,6 @@
|
||||
4B44EBF41DC987AE00A7820C /* AllSuiteA.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = AllSuiteA.bin; path = AllSuiteA/AllSuiteA.bin; sourceTree = "<group>"; };
|
||||
4B44EBF61DC9883B00A7820C /* 6502_functional_test.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = 6502_functional_test.bin; path = "Klaus Dormann/6502_functional_test.bin"; sourceTree = "<group>"; };
|
||||
4B44EBF81DC9898E00A7820C /* BCDTEST_beeb */ = {isa = PBXFileReference; lastKnownFileType = file; name = BCDTEST_beeb; path = BCDTest/BCDTEST_beeb; sourceTree = "<group>"; };
|
||||
4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMPatchedTrack.cpp; sourceTree = "<group>"; };
|
||||
4B4518721F75E91800926311 /* PCMPatchedTrack.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMPatchedTrack.hpp; sourceTree = "<group>"; };
|
||||
4B4518731F75E91800926311 /* PCMSegment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMSegment.cpp; sourceTree = "<group>"; };
|
||||
4B4518741F75E91800926311 /* PCMSegment.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = PCMSegment.hpp; sourceTree = "<group>"; };
|
||||
4B4518751F75E91800926311 /* PCMTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMTrack.cpp; sourceTree = "<group>"; };
|
||||
@ -1849,12 +1843,10 @@
|
||||
4B4518701F75E91800926311 /* Track */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */,
|
||||
4B4518731F75E91800926311 /* PCMSegment.cpp */,
|
||||
4B4518751F75E91800926311 /* PCMTrack.cpp */,
|
||||
4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */,
|
||||
4B4518771F75E91800926311 /* UnformattedTrack.cpp */,
|
||||
4B4518721F75E91800926311 /* PCMPatchedTrack.hpp */,
|
||||
4B4518741F75E91800926311 /* PCMSegment.hpp */,
|
||||
4B4518761F75E91800926311 /* PCMTrack.hpp */,
|
||||
4B4518881F75ECB100926311 /* Track.hpp */,
|
||||
@ -2789,7 +2781,6 @@
|
||||
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */,
|
||||
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
||||
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
||||
4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */,
|
||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
|
||||
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
|
||||
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
|
||||
@ -3639,7 +3630,6 @@
|
||||
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */,
|
||||
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
|
||||
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
|
||||
4B055AAB1FAE85FD0060FFFF /* PCMPatchedTrack.cpp in Sources */,
|
||||
4B055AC71FAE9AEE0060FFFF /* TIA.cpp in Sources */,
|
||||
4B055AD21FAE9B0B0060FFFF /* Keyboard.cpp in Sources */,
|
||||
4B89451B201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
|
||||
@ -3812,7 +3802,6 @@
|
||||
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */,
|
||||
4B894532201967B4007DE474 /* 6502.cpp in Sources */,
|
||||
4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */,
|
||||
4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */,
|
||||
4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */,
|
||||
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */,
|
||||
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,
|
||||
@ -3964,7 +3953,6 @@
|
||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
|
||||
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
|
||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
|
||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
|
||||
4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -71,6 +71,7 @@
|
||||
buildConfiguration = "Debug"
|
||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||
enableAddressSanitizer = "YES"
|
||||
enableASanStackUseAfterReturn = "YES"
|
||||
disableMainThreadChecker = "YES"
|
||||
launchStyle = "0"
|
||||
|
@ -1,195 +0,0 @@
|
||||
//
|
||||
// PCMPatchedTrackTests.m
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 17/12/2016.
|
||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#import <XCTest/XCTest.h>
|
||||
|
||||
#include "PCMTrack.hpp"
|
||||
#include "PCMPatchedTrack.hpp"
|
||||
|
||||
@interface PCMPatchedTrackTests : XCTestCase
|
||||
@end
|
||||
|
||||
@implementation PCMPatchedTrackTests
|
||||
|
||||
#pragma mark - Prebuilt tracks
|
||||
|
||||
- (std::shared_ptr<Storage::Disk::Track>)togglingTrack {
|
||||
Storage::Disk::PCMSegment segment;
|
||||
segment.data = { 0xff, 0xff, 0xff, 0xff };
|
||||
segment.number_of_bits = 32;
|
||||
return std::shared_ptr<Storage::Disk::Track>(new Storage::Disk::PCMTrack(segment));
|
||||
}
|
||||
|
||||
- (std::shared_ptr<Storage::Disk::Track>)patchableTogglingTrack {
|
||||
std::shared_ptr<Storage::Disk::Track> track = self.togglingTrack;
|
||||
return std::shared_ptr<Storage::Disk::Track>(new Storage::Disk::PCMPatchedTrack(track));
|
||||
}
|
||||
|
||||
- (std::shared_ptr<Storage::Disk::Track>)fourSegmentPatchedTrack {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
|
||||
Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(patchableTrack.get());
|
||||
|
||||
for(int c = 0; c < 4; c++) {
|
||||
Storage::Disk::PCMSegment segment;
|
||||
segment.data = {0xff};
|
||||
segment.number_of_bits = 8;
|
||||
segment.length_of_a_bit.length = 1;
|
||||
segment.length_of_a_bit.clock_rate = 32;
|
||||
patchable->add_segment(Storage::Time(c, 4), segment, false);
|
||||
}
|
||||
|
||||
return patchableTrack;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (std::vector<Storage::Disk::Track::Event>)eventsFromTrack:(std::shared_ptr<Storage::Disk::Track>)track {
|
||||
std::vector<Storage::Disk::Track::Event> events;
|
||||
while(1) {
|
||||
events.push_back(track->get_next_event());
|
||||
if(events.back().type == Storage::Disk::Track::Event::IndexHole) break;
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
- (Storage::Time)timeForEvents:(const std::vector<Storage::Disk::Track::Event> &)events {
|
||||
Storage::Time result(0);
|
||||
for(const auto &event : events) {
|
||||
result += event.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
- (void)patchTrack:(std::shared_ptr<Storage::Disk::Track>)track withSegment:(Storage::Disk::PCMSegment)segment atTime:(Storage::Time)time {
|
||||
Storage::Disk::PCMPatchedTrack *patchable = static_cast<Storage::Disk::PCMPatchedTrack *>(track.get());
|
||||
patchable->add_segment(time, segment, false);
|
||||
}
|
||||
|
||||
#pragma mark - Repeating Asserts
|
||||
|
||||
- (void)assertOneThirtyTwosForTrack:(std::shared_ptr<Storage::Disk::Track>)track {
|
||||
// Confirm that there are now flux transitions (just the first five will do)
|
||||
// located 1/32nd of a rotation apart.
|
||||
for(int c = 0; c < 5; c++) {
|
||||
Storage::Disk::Track::Event event = track->get_next_event();
|
||||
XCTAssert(
|
||||
event.length == (c ? Storage::Time(1, 32) : Storage::Time(1, 64)),
|
||||
@"flux transitions should be 1/32nd of a track apart");
|
||||
}
|
||||
}
|
||||
|
||||
- (void)assertEvents:(const std::vector<Storage::Disk::Track::Event> &)events hasEntries:(size_t)numberOfEntries withEntry:(size_t)entry ofLength:(Storage::Time)time {
|
||||
XCTAssert(events.size() == numberOfEntries, @"Should be %zu total events", numberOfEntries);
|
||||
|
||||
XCTAssert(events[entry].length == time, @"Event %zu should have been %d/%d long, was %d/%d", entry, time.length, time.clock_rate, events[entry].length.length, events[entry].length.clock_rate);
|
||||
|
||||
Storage::Time eventTime = [self timeForEvents:events];
|
||||
XCTAssert(eventTime == Storage::Time(1), @"Total track length should be 1; was %d/%d", eventTime.length, eventTime.clock_rate);
|
||||
}
|
||||
|
||||
#pragma mark - Unpatched tracks
|
||||
|
||||
- (void)testUnpatchedRawTrack {
|
||||
[self assertOneThirtyTwosForTrack:self.togglingTrack];
|
||||
}
|
||||
|
||||
- (void)testUnpatchedTrack {
|
||||
[self assertOneThirtyTwosForTrack:self.patchableTogglingTrack];
|
||||
}
|
||||
|
||||
#pragma mark - Insertions affecting one existing segment
|
||||
|
||||
- (void)testSingleSplice {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 1, {0xff}) atTime:Storage::Time(3, 128)];
|
||||
|
||||
std::vector<Storage::Disk::Track::Event> events = [self eventsFromTrack:patchableTrack];
|
||||
Storage::Time total_length = [self timeForEvents:events];
|
||||
|
||||
XCTAssert(events.size() == 33, @"Should still be 33 total events");
|
||||
XCTAssert(events[0].length == Storage::Time(1, 64), @"First event should be after 1/64 as usual");
|
||||
XCTAssert(events[1].length == Storage::Time(3, 128), @"Second event should be 3/128 later"); // ... as it was inserted at 3/128 and runs at the same rate as the main data, so first inserted event is at 3/128+1/64-1/64
|
||||
XCTAssert(events[2].length == Storage::Time(5, 128), @"Should still be 33 total events"); // 1/64 = 2/128 to exit the patch, plus 3/128 to get to the next event, having spliced in 1/128 ahead of the normal clock
|
||||
XCTAssert(total_length == Storage::Time(1), @"Total track length should still be 1");
|
||||
}
|
||||
|
||||
- (void)testLeftReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(0)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:0 ofLength:Storage::Time(33, 64)];
|
||||
}
|
||||
|
||||
- (void)testRightReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 2)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:16 ofLength:Storage::Time(33, 64)];
|
||||
}
|
||||
|
||||
#pragma mark - Insertions affecting three existing segments
|
||||
|
||||
- (void)testMultiSegmentTrack {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:33 withEntry:4 ofLength:Storage::Time(1, 32)];
|
||||
}
|
||||
|
||||
- (void)testMultiTrimBothSideReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 16), 8, {0x00}) atTime:Storage::Time(1, 8)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:17 withEntry:4 ofLength:Storage::Time(17, 32)];
|
||||
}
|
||||
|
||||
- (void)testMultiTrimRightReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)];
|
||||
}
|
||||
|
||||
- (void)testMultiTrimLeftReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 4)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:8 ofLength:Storage::Time(13, 32)];
|
||||
}
|
||||
|
||||
#pragma mark - Insertions affecting two existing segments
|
||||
|
||||
- (void)testTwoSegmentOverlap {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(1, 32), 8, {0x00}) atTime:Storage::Time(1, 8)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:25 withEntry:4 ofLength:Storage::Time(9, 32)];
|
||||
}
|
||||
|
||||
- (void)testTwoSegmentRightReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(1, 8)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:4 ofLength:Storage::Time(13, 32)];
|
||||
}
|
||||
|
||||
- (void)testTwoSegmentLeftReplace {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.fourSegmentPatchedTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(3, 8), 1, {0x00}) atTime:Storage::Time(0)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:21 withEntry:0 ofLength:Storage::Time(25, 64)];
|
||||
}
|
||||
|
||||
#pragma mark - Wrapping segment
|
||||
|
||||
- (void)testWrappingSegment {
|
||||
std::shared_ptr<Storage::Disk::Track> patchableTrack = self.patchableTogglingTrack;
|
||||
[self patchTrack:patchableTrack withSegment:Storage::Disk::PCMSegment(Storage::Time(5, 2), 1, {0x00}) atTime:Storage::Time(0)];
|
||||
|
||||
[self assertEvents:[self eventsFromTrack:patchableTrack] hasEntries:1 withEntry:0 ofLength:Storage::Time(1, 1)];
|
||||
}
|
||||
|
||||
@end
|
@ -17,11 +17,8 @@
|
||||
|
||||
- (Storage::Disk::PCMSegmentEventSource)segmentSource
|
||||
{
|
||||
Storage::Disk::PCMSegment alternatingFFs;
|
||||
alternatingFFs.data = {0xff, 0x00, 0xff, 0x00};
|
||||
alternatingFFs.length_of_a_bit.length = 1;
|
||||
alternatingFFs.length_of_a_bit.clock_rate = 10;
|
||||
alternatingFFs.number_of_bits = 32;
|
||||
std::vector<uint8_t> data = {0xff, 0x00, 0xff, 0x00};
|
||||
Storage::Disk::PCMSegment alternatingFFs(Storage::Time(1, 10), data.size()*8, data);
|
||||
return Storage::Disk::PCMSegmentEventSource(alternatingFFs);
|
||||
}
|
||||
|
||||
|
@ -19,13 +19,11 @@
|
||||
{
|
||||
Storage::Disk::PCMSegment quickSegment, slowSegment;
|
||||
|
||||
quickSegment.data = {0xff};
|
||||
quickSegment.number_of_bits = 8;
|
||||
quickSegment.data = {true, true, true, true, true, true, true, true};
|
||||
quickSegment.length_of_a_bit.length = 1;
|
||||
quickSegment.length_of_a_bit.clock_rate = 100;
|
||||
|
||||
slowSegment.data = {0xff};
|
||||
slowSegment.number_of_bits = 8;
|
||||
slowSegment.data = {true, true, true, true, true, true, true, true};
|
||||
slowSegment.length_of_a_bit.length = 1;
|
||||
slowSegment.length_of_a_bit.clock_rate = 3;
|
||||
|
||||
@ -55,19 +53,16 @@
|
||||
std::vector<Storage::Disk::PCMSegment> segments;
|
||||
|
||||
Storage::Disk::PCMSegment sync_segment;
|
||||
sync_segment.data.resize(10);
|
||||
sync_segment.number_of_bits = 10*8;
|
||||
memset(sync_segment.data.data(), 0xff, sync_segment.data.size());
|
||||
sync_segment.data.resize(10*8);
|
||||
std::fill(sync_segment.data.begin(), sync_segment.data.end(), true);
|
||||
|
||||
Storage::Disk::PCMSegment header_segment;
|
||||
header_segment.data.resize(14);
|
||||
header_segment.number_of_bits = 14*8;
|
||||
memset(header_segment.data.data(), 0xff, header_segment.data.size());
|
||||
header_segment.data.resize(14*8);
|
||||
std::fill(header_segment.data.begin(), header_segment.data.end(), true);
|
||||
|
||||
Storage::Disk::PCMSegment data_segment;
|
||||
data_segment.data.resize(349);
|
||||
data_segment.number_of_bits = 349*8;
|
||||
memset(data_segment.data.data(), 0xff, data_segment.data.size());
|
||||
data_segment.data.resize(349*8);
|
||||
std::fill(data_segment.data.begin(), data_segment.data.end(), true);
|
||||
|
||||
for(std::size_t c = 0; c < 16; ++c) {
|
||||
segments.push_back(sync_segment);
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include "../Drive.hpp"
|
||||
#include "../DPLL/DigitalPhaseLockedLoop.hpp"
|
||||
#include "../Track/PCMSegment.hpp"
|
||||
#include "../Track/PCMPatchedTrack.hpp"
|
||||
|
||||
#include "../../../ClockReceiver/ClockReceiver.hpp"
|
||||
#include "../../../ClockReceiver/ClockingHintSource.hpp"
|
||||
|
@ -310,14 +310,17 @@ void Drive::write_bit(bool value) {
|
||||
}
|
||||
|
||||
void Drive::end_writing() {
|
||||
static const size_t high_resolution_track_rate = 500000;
|
||||
|
||||
if(!is_reading_) {
|
||||
is_reading_ = true;
|
||||
|
||||
if(!patched_track_) {
|
||||
// Avoid creating a new patched track if this one is already patched
|
||||
patched_track_ = std::dynamic_pointer_cast<PCMPatchedTrack>(track_);
|
||||
if(!patched_track_) {
|
||||
patched_track_.reset(new PCMPatchedTrack(track_));
|
||||
patched_track_ = std::dynamic_pointer_cast<PCMTrack>(track_);
|
||||
if(!patched_track_ || !patched_track_->is_resampled_clone()) {
|
||||
Track *tr = track_.get();
|
||||
patched_track_.reset(PCMTrack::resampled_clone(tr, high_resolution_track_rate));
|
||||
}
|
||||
}
|
||||
patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
#include "Disk.hpp"
|
||||
#include "Track/PCMSegment.hpp"
|
||||
#include "Track/PCMPatchedTrack.hpp"
|
||||
#include "Track/PCMTrack.hpp"
|
||||
|
||||
#include "../TimedEventLoop.hpp"
|
||||
#include "../../Activity/Observer.hpp"
|
||||
@ -168,8 +168,8 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
||||
bool clamp_writing_to_index_hole_ = false;
|
||||
|
||||
// If writing is occurring then the drive will be accumulating a write segment,
|
||||
// for addition to a patched track.
|
||||
std::shared_ptr<PCMPatchedTrack> patched_track_;
|
||||
// for addition to a (high-resolution) PCM track.
|
||||
std::shared_ptr<PCMTrack> patched_track_;
|
||||
PCMSegment write_segment_;
|
||||
Time write_start_time_;
|
||||
|
||||
|
@ -1,222 +0,0 @@
|
||||
//
|
||||
// PCMPatchedTrack.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 15/12/2016.
|
||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "PCMPatchedTrack.hpp"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
PCMPatchedTrack::PCMPatchedTrack(std::shared_ptr<Track> underlying_track) :
|
||||
underlying_track_(underlying_track) {
|
||||
const Time zero(0);
|
||||
const Time one(1);
|
||||
periods_.emplace_back(zero, one, zero, nullptr);
|
||||
active_period_ = periods_.begin();
|
||||
underlying_track_->seek_to(zero);
|
||||
}
|
||||
|
||||
PCMPatchedTrack::PCMPatchedTrack(const PCMPatchedTrack &original) {
|
||||
underlying_track_.reset(original.underlying_track_->clone());
|
||||
periods_ = original.periods_;
|
||||
active_period_ = periods_.begin();
|
||||
}
|
||||
|
||||
Track *PCMPatchedTrack::clone() const {
|
||||
return new PCMPatchedTrack(*this);
|
||||
}
|
||||
|
||||
void PCMPatchedTrack::add_segment(const Time &start_time, const PCMSegment &segment, bool clamp_to_index_hole) {
|
||||
std::shared_ptr<PCMSegmentEventSource> event_source(new PCMSegmentEventSource(segment));
|
||||
|
||||
Time zero(0);
|
||||
Time one(1);
|
||||
Time end_time = start_time + event_source->get_length();
|
||||
if(clamp_to_index_hole && end_time > one) {
|
||||
end_time = one;
|
||||
}
|
||||
Period insertion_period(start_time, end_time, zero, event_source);
|
||||
|
||||
// the new segment may wrap around, so divide it up into track-length parts if required
|
||||
assert(insertion_period.start_time <= one);
|
||||
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.segment_start_time += one;
|
||||
insertion_period.start_time = zero;
|
||||
insertion_period.end_time = next_end_time;
|
||||
}
|
||||
insert_period(insertion_period);
|
||||
|
||||
// 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.
|
||||
insertion_error_ = current_time_ - seek_to(current_time_);
|
||||
}
|
||||
|
||||
void PCMPatchedTrack::insert_period(const Period &period) {
|
||||
// find the existing period that the new period starts in
|
||||
std::vector<Period>::iterator start_period = periods_.begin();
|
||||
while(start_period->end_time <= period.start_time) start_period++;
|
||||
|
||||
// find the existing period that the new period end in
|
||||
std::vector<Period>::iterator end_period = start_period;
|
||||
while(end_period->end_time < period.end_time) end_period++;
|
||||
|
||||
// perform a division if called for
|
||||
if(start_period == end_period) {
|
||||
if(start_period->start_time == period.start_time) {
|
||||
if(start_period->end_time == period.end_time) {
|
||||
// period has the same start and end time as start_period. So just replace it.
|
||||
*start_period = period;
|
||||
} else {
|
||||
// period has the same start time as start_period but a different end time.
|
||||
// So trim the left-hand side of start_period and insert the new period in front.
|
||||
start_period->push_start_to_time(period.end_time);
|
||||
periods_.insert(start_period, period);
|
||||
}
|
||||
} else {
|
||||
if(start_period->end_time == period.end_time) {
|
||||
// period has the same end time as start_period but a different start time.
|
||||
// So trim the right-hand side of start_period and insert the new period afterwards
|
||||
start_period->trim_end_to_time(period.start_time);
|
||||
periods_.insert(start_period + 1, period);
|
||||
} else {
|
||||
// start_period has an earlier start and a later end than period. So copy it,
|
||||
// trim the right off the original and the left off the copy, then insert the
|
||||
// new period and the copy after start_period
|
||||
Period right_period = *start_period;
|
||||
|
||||
right_period.push_start_to_time(period.end_time);
|
||||
start_period->trim_end_to_time(period.start_time);
|
||||
|
||||
// the iterator isn't guaranteed to survive the insert, e.g. if it causes a resize
|
||||
std::vector<Period>::difference_type offset = start_period - periods_.begin();
|
||||
periods_.insert(start_period + 1, period);
|
||||
periods_.insert(periods_.begin() + offset + 2, right_period);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool should_insert = false;
|
||||
std::vector<Period>::difference_type insertion_offset = 0;
|
||||
|
||||
if(start_period->start_time == period.start_time) {
|
||||
// start_period starts at the same place as period. Period then
|
||||
// ends after start_period. So replace.
|
||||
*start_period = period;
|
||||
should_insert = false;
|
||||
} else {
|
||||
// start_period starts before period. So trim and plan to insert afterwards.
|
||||
start_period->trim_end_to_time(period.start_time);
|
||||
should_insert = true;
|
||||
insertion_offset = start_period + 1 - periods_.begin();
|
||||
}
|
||||
|
||||
if(end_period->end_time == period.end_time) {
|
||||
// end_period ends exactly when period does. So include it from the list to delete
|
||||
end_period++;
|
||||
} else {
|
||||
end_period->push_start_to_time(period.end_time);
|
||||
}
|
||||
|
||||
// remove everything that is exiting in between
|
||||
periods_.erase(start_period + 1, end_period);
|
||||
|
||||
// insert the new period if required
|
||||
if(should_insert)
|
||||
periods_.insert(periods_.begin()+insertion_offset, period);
|
||||
}
|
||||
}
|
||||
|
||||
Track::Event PCMPatchedTrack::get_next_event() {
|
||||
const Time one(1);
|
||||
const Time zero(0);
|
||||
Time extra_time(0);
|
||||
Time period_error(0);
|
||||
|
||||
while(1) {
|
||||
// get the next event from the current active period
|
||||
Track::Event event;
|
||||
if(active_period_->event_source) event = active_period_->event_source->get_next_event();
|
||||
else event = underlying_track_->get_next_event();
|
||||
|
||||
// see what time that gets us to. If it's still within the current period, return the found event
|
||||
Time event_time = current_time_ + event.length - period_error - insertion_error_;
|
||||
if(event_time < active_period_->end_time) {
|
||||
current_time_ = event_time;
|
||||
// TODO: this is spelt out in three steps because times don't necessarily do the sensible
|
||||
// thing when 'negative' if intermediate result get simplified in the meantime. So fix Time.
|
||||
event.length += extra_time;
|
||||
event.length -= period_error;
|
||||
event.length -= insertion_error_;
|
||||
return event;
|
||||
}
|
||||
insertion_error_.set_zero();
|
||||
|
||||
// otherwise move time back to the end of the outgoing period, accumulating the error into
|
||||
// extra_time, and advance the extra period
|
||||
extra_time += (active_period_->end_time - current_time_);
|
||||
current_time_ = active_period_->end_time;
|
||||
active_period_++;
|
||||
|
||||
// test for having reached the end of the track
|
||||
if(active_period_ == periods_.end()) {
|
||||
// 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 = current_time_ - underlying_track_->seek_to(current_time_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Storage::Time PCMPatchedTrack::seek_to(const Time &time_since_index_hole) {
|
||||
// start at the beginning and continue while segments end before reaching the time sought
|
||||
active_period_ = periods_.begin();
|
||||
while(active_period_->end_time < time_since_index_hole) {
|
||||
assert(active_period_ != periods_.end());
|
||||
active_period_++;
|
||||
}
|
||||
|
||||
// allow whatever storage represents the period found to perform its seek; calculation for periods
|
||||
// with an event source is, in effect: seek_to(offset_into_segment + distance_into_period) - offset_into_segment.
|
||||
if(active_period_->event_source)
|
||||
current_time_ = active_period_->event_source->seek_to(active_period_->segment_start_time + time_since_index_hole - active_period_->start_time) + active_period_->start_time - active_period_->segment_start_time;
|
||||
else
|
||||
current_time_ = underlying_track_->seek_to(time_since_index_hole);
|
||||
|
||||
// The assert below is disabled as it assumes too much about total precision.
|
||||
// assert(current_time_ <= time_since_index_hole);
|
||||
return current_time_;
|
||||
}
|
||||
|
||||
PCMPatchedTrack::Period::Period(const Period &original) :
|
||||
start_time(original.start_time), end_time(original.end_time), segment_start_time(original.segment_start_time) {
|
||||
if(original.event_source) event_source.reset(new PCMSegmentEventSource(*original.event_source));
|
||||
}
|
||||
|
||||
void PCMPatchedTrack::Period::push_start_to_time(const Storage::Time &new_start_time) {
|
||||
segment_start_time += new_start_time - start_time;
|
||||
start_time = new_start_time;
|
||||
}
|
||||
|
||||
void PCMPatchedTrack::Period::trim_end_to_time(const Storage::Time &new_end_time) {
|
||||
end_time = new_end_time;
|
||||
}
|
@ -1,75 +0,0 @@
|
||||
//
|
||||
// PCMPatchedTrack.hpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 15/12/2016.
|
||||
// Copyright 2016 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#ifndef PCMPatchedTrack_hpp
|
||||
#define PCMPatchedTrack_hpp
|
||||
|
||||
#include "Track.hpp"
|
||||
#include "PCMSegment.hpp"
|
||||
|
||||
namespace Storage {
|
||||
namespace Disk {
|
||||
|
||||
/*!
|
||||
A subclass of @c Track that patches an existing track with PCM segments.
|
||||
*/
|
||||
class PCMPatchedTrack: public Track {
|
||||
public:
|
||||
/*!
|
||||
Constructs a @c PCMPatchedTrack that will return events from @c underlying_track in
|
||||
regions where it has not had alternative PCM data installed.
|
||||
*/
|
||||
PCMPatchedTrack(std::shared_ptr<Track> underlying_track);
|
||||
|
||||
/*!
|
||||
Copy constructor, for Track.
|
||||
*/
|
||||
PCMPatchedTrack(const PCMPatchedTrack &);
|
||||
|
||||
/*!
|
||||
Replaces whatever is currently on the track from @c start_position to @c start_position + segment length
|
||||
with the contents of @c segment.
|
||||
|
||||
@param start_time The time at which this segment begins. Must be in the range [0, 1).
|
||||
@param segment The PCM segment to add.
|
||||
@param clamp_to_index_hole If @c true then the new segment will be truncated if it overruns the index hole;
|
||||
it will otherwise write over the index hole and continue.
|
||||
*/
|
||||
void add_segment(const Time &start_time, const PCMSegment &segment, bool clamp_to_index_hole);
|
||||
|
||||
// To satisfy Storage::Disk::Track
|
||||
Event get_next_event() override;
|
||||
Time seek_to(const Time &time_since_index_hole) override;
|
||||
Track *clone() const override;
|
||||
|
||||
private:
|
||||
std::shared_ptr<Track> underlying_track_;
|
||||
|
||||
struct Period {
|
||||
Time start_time, end_time;
|
||||
Time segment_start_time;
|
||||
std::shared_ptr<PCMSegmentEventSource> event_source; // nullptr => use the underlying track
|
||||
|
||||
void push_start_to_time(const Storage::Time &new_start_time);
|
||||
void trim_end_to_time(const Storage::Time &new_end_time);
|
||||
|
||||
Period(const Time &start_time, const Time &end_time, const Time &segment_start_time, std::shared_ptr<PCMSegmentEventSource> event_source) :
|
||||
start_time(start_time), end_time(end_time), segment_start_time(segment_start_time), event_source(event_source) {}
|
||||
Period(const Period &);
|
||||
};
|
||||
std::vector<Period> periods_;
|
||||
std::vector<Period>::iterator active_period_;
|
||||
Time current_time_, insertion_error_;
|
||||
|
||||
void insert_period(const Period &period);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* PCMPatchedTrack_hpp */
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "PCMTrack.hpp"
|
||||
#include "../../../NumberTheory/Factors.hpp"
|
||||
#include "../../../Outputs/Log.hpp"
|
||||
|
||||
using namespace Storage::Disk;
|
||||
|
||||
@ -54,11 +55,25 @@ PCMTrack::PCMTrack(unsigned int bits_per_track) : PCMTrack() {
|
||||
segment_event_sources_.emplace_back(segment);
|
||||
}
|
||||
|
||||
PCMTrack *PCMTrack::resampled_clone(Track *original, size_t bits_per_track) {
|
||||
PCMTrack *pcm_original = dynamic_cast<PCMTrack *>(original);
|
||||
if(pcm_original) {
|
||||
return pcm_original->resampled_clone(bits_per_track);
|
||||
}
|
||||
|
||||
ERROR("NOT IMPLEMENTED: resampling non-PCMTracks");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PCMTrack::is_resampled_clone() {
|
||||
return is_resampled_clone_;
|
||||
}
|
||||
|
||||
Track *PCMTrack::clone() const {
|
||||
return new PCMTrack(*this);
|
||||
}
|
||||
|
||||
Track *PCMTrack::resampled_clone(size_t bits_per_track) {
|
||||
PCMTrack *PCMTrack::resampled_clone(size_t bits_per_track) {
|
||||
// Create an empty track.
|
||||
PCMTrack *const new_track = new PCMTrack(static_cast<unsigned int>(bits_per_track));
|
||||
|
||||
@ -70,6 +85,7 @@ Track *PCMTrack::resampled_clone(size_t bits_per_track) {
|
||||
start_time += source.length();
|
||||
}
|
||||
|
||||
new_track->is_resampled_clone_ = true;
|
||||
return new_track;
|
||||
}
|
||||
|
||||
@ -140,12 +156,18 @@ void PCMTrack::add_segment(const Time &start_time, const PCMSegment &segment, bo
|
||||
const Time end_time = start_time + segment.length();
|
||||
const size_t start_bit = start_time.length * destination.data.size() / start_time.clock_rate;
|
||||
const size_t end_bit = end_time.length * destination.data.size() / end_time.clock_rate;
|
||||
const size_t target_width = end_bit - start_bit;
|
||||
|
||||
// If clamping is applied, just put a hard cut-off at the index hole.
|
||||
// if(clamp_to_index_hole) {
|
||||
// end_bit = std::min(end_bit, destination.data.size());
|
||||
// }
|
||||
// !!TODO!! Deal with wrapping and clamping.
|
||||
|
||||
// Reset the destination.
|
||||
std::fill(destination.data.begin() + static_cast<off_t>(start_bit), destination.data.begin() + static_cast<off_t>(end_bit), false);
|
||||
|
||||
// Step through the source data, and for each true map to a location in the destination and set it.
|
||||
const size_t target_width = end_bit - start_bit;
|
||||
const size_t half_offset = target_width / (2 * segment.data.size());
|
||||
for(size_t bit = 0; bit < segment.data.size(); ++bit) {
|
||||
if(segment.data[bit]) {
|
||||
|
@ -43,6 +43,11 @@ class PCMTrack: public Track {
|
||||
*/
|
||||
PCMTrack(const PCMTrack &);
|
||||
|
||||
/*!
|
||||
Creates a PCMTrack by sampling the original at a rate of @c bits_per_track.
|
||||
*/
|
||||
static PCMTrack *resampled_clone(Track *original, size_t bits_per_track);
|
||||
|
||||
// as per @c Track
|
||||
Event get_next_event() override;
|
||||
Time seek_to(const Time &time_since_index_hole) override;
|
||||
@ -50,7 +55,8 @@ class PCMTrack: public Track {
|
||||
|
||||
// Obtains a copy of this track, flattened to a single PCMSegment, which
|
||||
// consists of @c bits_per_track potential flux transition points.
|
||||
Track *resampled_clone(size_t bits_per_track);
|
||||
PCMTrack *resampled_clone(size_t bits_per_track);
|
||||
bool is_resampled_clone();
|
||||
|
||||
/*!
|
||||
Replaces whatever is currently on the track from @c start_position to @c start_position + segment length
|
||||
@ -80,6 +86,7 @@ class PCMTrack: public Track {
|
||||
std::size_t segment_pointer_;
|
||||
|
||||
PCMTrack();
|
||||
bool is_resampled_clone_ = false;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user