mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-01 11:49:58 +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_) {}
|
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.
|
/// @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);
|
return Cycles(length_ >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,7 +43,6 @@
|
|||||||
4B055AA81FAE85EF0060FFFF /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; };
|
4B055AA81FAE85EF0060FFFF /* Shifter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B7136871F78725F008B8ED9 /* Shifter.cpp */; };
|
||||||
4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
|
4B055AA91FAE85EF0060FFFF /* CommodoreGCR.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BB697CC1D4BA44400248BDF /* CommodoreGCR.cpp */; };
|
||||||
4B055AAA1FAE85F50060FFFF /* CPM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B3FE75C1F3CF68B00448EE4 /* CPM.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 */; };
|
4B055AAC1FAE85FD0060FFFF /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
|
||||||
4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
4B055AAD1FAE85FD0060FFFF /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
||||||
4B055AAE1FAE85FD0060FFFF /* TrackSerialiser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.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 */; };
|
4B0E61071FF34737002A9DBD /* MSX.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0E61051FF34737002A9DBD /* MSX.cpp */; };
|
||||||
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
|
4B0F94FE208C1A1600FE41D9 /* NIB.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B0F94FC208C1A1600FE41D9 /* NIB.cpp */; };
|
||||||
4B0F94FF208C1A1600FE41D9 /* 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 */; };
|
4B121F9B1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */; };
|
||||||
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
|
4B12C0ED1FCFA98D005BFD93 /* Keyboard.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B12C0EB1FCFA98D005BFD93 /* Keyboard.cpp */; };
|
||||||
4B12C0EE1FCFAD1A005BFD93 /* 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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
4B4518821F75E91A00926311 /* PCMSegment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518731F75E91800926311 /* PCMSegment.cpp */; };
|
||||||
4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
4B4518831F75E91A00926311 /* PCMTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518751F75E91800926311 /* PCMTrack.cpp */; };
|
||||||
4B4518841F75E91A00926311 /* UnformattedTrack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B4518771F75E91800926311 /* UnformattedTrack.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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
4B4518751F75E91800926311 /* PCMTrack.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PCMTrack.cpp; sourceTree = "<group>"; };
|
||||||
@ -1849,12 +1843,10 @@
|
|||||||
4B4518701F75E91800926311 /* Track */ = {
|
4B4518701F75E91800926311 /* Track */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
4B4518711F75E91800926311 /* PCMPatchedTrack.cpp */,
|
|
||||||
4B4518731F75E91800926311 /* PCMSegment.cpp */,
|
4B4518731F75E91800926311 /* PCMSegment.cpp */,
|
||||||
4B4518751F75E91800926311 /* PCMTrack.cpp */,
|
4B4518751F75E91800926311 /* PCMTrack.cpp */,
|
||||||
4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */,
|
4BBFFEE51F7B27F1005F3FEB /* TrackSerialiser.cpp */,
|
||||||
4B4518771F75E91800926311 /* UnformattedTrack.cpp */,
|
4B4518771F75E91800926311 /* UnformattedTrack.cpp */,
|
||||||
4B4518721F75E91800926311 /* PCMPatchedTrack.hpp */,
|
|
||||||
4B4518741F75E91800926311 /* PCMSegment.hpp */,
|
4B4518741F75E91800926311 /* PCMSegment.hpp */,
|
||||||
4B4518761F75E91800926311 /* PCMTrack.hpp */,
|
4B4518761F75E91800926311 /* PCMTrack.hpp */,
|
||||||
4B4518881F75ECB100926311 /* Track.hpp */,
|
4B4518881F75ECB100926311 /* Track.hpp */,
|
||||||
@ -2789,7 +2781,6 @@
|
|||||||
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */,
|
4B5073091DDFCFDF00C48FBD /* ArrayBuilderTests.mm */,
|
||||||
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
4B924E981E74D22700B76AF1 /* AtariStaticAnalyserTests.mm */,
|
||||||
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
4BB2A9AE1E13367E001A5C23 /* CRCTests.mm */,
|
||||||
4B121F941E05E66800BFDA12 /* PCMPatchedTrackTests.mm */,
|
|
||||||
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
|
4B121F9A1E06293F00BFDA12 /* PCMSegmentEventSourceTests.mm */,
|
||||||
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
|
4BD4A8CF1E077FD20020D856 /* PCMTrackTests.mm */,
|
||||||
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
|
4B2AF8681E513FC20027EE29 /* TIATests.mm */,
|
||||||
@ -3639,7 +3630,6 @@
|
|||||||
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */,
|
4B12C0EE1FCFAD1A005BFD93 /* Keyboard.cpp in Sources */,
|
||||||
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
|
4B055AE81FAE9B7B0060FFFF /* FIRFilter.cpp in Sources */,
|
||||||
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
|
4B055A901FAE85A90060FFFF /* TimedEventLoop.cpp in Sources */,
|
||||||
4B055AAB1FAE85FD0060FFFF /* PCMPatchedTrack.cpp in Sources */,
|
|
||||||
4B055AC71FAE9AEE0060FFFF /* TIA.cpp in Sources */,
|
4B055AC71FAE9AEE0060FFFF /* TIA.cpp in Sources */,
|
||||||
4B055AD21FAE9B0B0060FFFF /* Keyboard.cpp in Sources */,
|
4B055AD21FAE9B0B0060FFFF /* Keyboard.cpp in Sources */,
|
||||||
4B89451B201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
|
4B89451B201967B4007DE474 /* ConfidenceSummary.cpp in Sources */,
|
||||||
@ -3812,7 +3802,6 @@
|
|||||||
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */,
|
4BD5F1951D13528900631CD1 /* CSBestEffortUpdater.mm in Sources */,
|
||||||
4B894532201967B4007DE474 /* 6502.cpp in Sources */,
|
4B894532201967B4007DE474 /* 6502.cpp in Sources */,
|
||||||
4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */,
|
4BDB61EC203285AE0048AF91 /* Atari2600OptionsPanel.swift in Sources */,
|
||||||
4B4518811F75E91A00926311 /* PCMPatchedTrack.cpp in Sources */,
|
|
||||||
4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */,
|
4BBB70A8202014E2002FE009 /* MultiCRTMachine.cpp in Sources */,
|
||||||
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */,
|
4B8805F71DCFF6C9003085B1 /* Commodore.cpp in Sources */,
|
||||||
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,
|
4BBF99181C8FBA6F0075DAFB /* TextureTarget.cpp in Sources */,
|
||||||
@ -3964,7 +3953,6 @@
|
|||||||
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
|
4B1D08061E0F7A1100763741 /* TimeTests.mm in Sources */,
|
||||||
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
|
4B08A2781EE39306008B7065 /* TestMachine.mm in Sources */,
|
||||||
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
|
4BFCA1271ECBE33200AC40C1 /* TestMachineZ80.mm in Sources */,
|
||||||
4B121F951E05E66800BFDA12 /* PCMPatchedTrackTests.mm in Sources */,
|
|
||||||
4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */,
|
4B322E011F5A2990004EB04C /* Z80AllRAM.cpp in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
|
enableAddressSanitizer = "YES"
|
||||||
enableASanStackUseAfterReturn = "YES"
|
enableASanStackUseAfterReturn = "YES"
|
||||||
disableMainThreadChecker = "YES"
|
disableMainThreadChecker = "YES"
|
||||||
launchStyle = "0"
|
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::PCMSegmentEventSource)segmentSource
|
||||||
{
|
{
|
||||||
Storage::Disk::PCMSegment alternatingFFs;
|
std::vector<uint8_t> data = {0xff, 0x00, 0xff, 0x00};
|
||||||
alternatingFFs.data = {0xff, 0x00, 0xff, 0x00};
|
Storage::Disk::PCMSegment alternatingFFs(Storage::Time(1, 10), data.size()*8, data);
|
||||||
alternatingFFs.length_of_a_bit.length = 1;
|
|
||||||
alternatingFFs.length_of_a_bit.clock_rate = 10;
|
|
||||||
alternatingFFs.number_of_bits = 32;
|
|
||||||
return Storage::Disk::PCMSegmentEventSource(alternatingFFs);
|
return Storage::Disk::PCMSegmentEventSource(alternatingFFs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,13 +19,11 @@
|
|||||||
{
|
{
|
||||||
Storage::Disk::PCMSegment quickSegment, slowSegment;
|
Storage::Disk::PCMSegment quickSegment, slowSegment;
|
||||||
|
|
||||||
quickSegment.data = {0xff};
|
quickSegment.data = {true, true, true, true, true, true, true, true};
|
||||||
quickSegment.number_of_bits = 8;
|
|
||||||
quickSegment.length_of_a_bit.length = 1;
|
quickSegment.length_of_a_bit.length = 1;
|
||||||
quickSegment.length_of_a_bit.clock_rate = 100;
|
quickSegment.length_of_a_bit.clock_rate = 100;
|
||||||
|
|
||||||
slowSegment.data = {0xff};
|
slowSegment.data = {true, true, true, true, true, true, true, true};
|
||||||
slowSegment.number_of_bits = 8;
|
|
||||||
slowSegment.length_of_a_bit.length = 1;
|
slowSegment.length_of_a_bit.length = 1;
|
||||||
slowSegment.length_of_a_bit.clock_rate = 3;
|
slowSegment.length_of_a_bit.clock_rate = 3;
|
||||||
|
|
||||||
@ -55,19 +53,16 @@
|
|||||||
std::vector<Storage::Disk::PCMSegment> segments;
|
std::vector<Storage::Disk::PCMSegment> segments;
|
||||||
|
|
||||||
Storage::Disk::PCMSegment sync_segment;
|
Storage::Disk::PCMSegment sync_segment;
|
||||||
sync_segment.data.resize(10);
|
sync_segment.data.resize(10*8);
|
||||||
sync_segment.number_of_bits = 10*8;
|
std::fill(sync_segment.data.begin(), sync_segment.data.end(), true);
|
||||||
memset(sync_segment.data.data(), 0xff, sync_segment.data.size());
|
|
||||||
|
|
||||||
Storage::Disk::PCMSegment header_segment;
|
Storage::Disk::PCMSegment header_segment;
|
||||||
header_segment.data.resize(14);
|
header_segment.data.resize(14*8);
|
||||||
header_segment.number_of_bits = 14*8;
|
std::fill(header_segment.data.begin(), header_segment.data.end(), true);
|
||||||
memset(header_segment.data.data(), 0xff, header_segment.data.size());
|
|
||||||
|
|
||||||
Storage::Disk::PCMSegment data_segment;
|
Storage::Disk::PCMSegment data_segment;
|
||||||
data_segment.data.resize(349);
|
data_segment.data.resize(349*8);
|
||||||
data_segment.number_of_bits = 349*8;
|
std::fill(data_segment.data.begin(), data_segment.data.end(), true);
|
||||||
memset(data_segment.data.data(), 0xff, data_segment.data.size());
|
|
||||||
|
|
||||||
for(std::size_t c = 0; c < 16; ++c) {
|
for(std::size_t c = 0; c < 16; ++c) {
|
||||||
segments.push_back(sync_segment);
|
segments.push_back(sync_segment);
|
||||||
|
@ -12,7 +12,6 @@
|
|||||||
#include "../Drive.hpp"
|
#include "../Drive.hpp"
|
||||||
#include "../DPLL/DigitalPhaseLockedLoop.hpp"
|
#include "../DPLL/DigitalPhaseLockedLoop.hpp"
|
||||||
#include "../Track/PCMSegment.hpp"
|
#include "../Track/PCMSegment.hpp"
|
||||||
#include "../Track/PCMPatchedTrack.hpp"
|
|
||||||
|
|
||||||
#include "../../../ClockReceiver/ClockReceiver.hpp"
|
#include "../../../ClockReceiver/ClockReceiver.hpp"
|
||||||
#include "../../../ClockReceiver/ClockingHintSource.hpp"
|
#include "../../../ClockReceiver/ClockingHintSource.hpp"
|
||||||
|
@ -310,14 +310,17 @@ void Drive::write_bit(bool value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Drive::end_writing() {
|
void Drive::end_writing() {
|
||||||
|
static const size_t high_resolution_track_rate = 500000;
|
||||||
|
|
||||||
if(!is_reading_) {
|
if(!is_reading_) {
|
||||||
is_reading_ = true;
|
is_reading_ = true;
|
||||||
|
|
||||||
if(!patched_track_) {
|
if(!patched_track_) {
|
||||||
// Avoid creating a new patched track if this one is already patched
|
// Avoid creating a new patched track if this one is already patched
|
||||||
patched_track_ = std::dynamic_pointer_cast<PCMPatchedTrack>(track_);
|
patched_track_ = std::dynamic_pointer_cast<PCMTrack>(track_);
|
||||||
if(!patched_track_) {
|
if(!patched_track_ || !patched_track_->is_resampled_clone()) {
|
||||||
patched_track_.reset(new PCMPatchedTrack(track_));
|
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_);
|
patched_track_->add_segment(write_start_time_, write_segment_, clamp_writing_to_index_hole_);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
#include "Disk.hpp"
|
#include "Disk.hpp"
|
||||||
#include "Track/PCMSegment.hpp"
|
#include "Track/PCMSegment.hpp"
|
||||||
#include "Track/PCMPatchedTrack.hpp"
|
#include "Track/PCMTrack.hpp"
|
||||||
|
|
||||||
#include "../TimedEventLoop.hpp"
|
#include "../TimedEventLoop.hpp"
|
||||||
#include "../../Activity/Observer.hpp"
|
#include "../../Activity/Observer.hpp"
|
||||||
@ -168,8 +168,8 @@ class Drive: public ClockingHint::Source, public TimedEventLoop {
|
|||||||
bool clamp_writing_to_index_hole_ = false;
|
bool clamp_writing_to_index_hole_ = false;
|
||||||
|
|
||||||
// If writing is occurring then the drive will be accumulating a write segment,
|
// If writing is occurring then the drive will be accumulating a write segment,
|
||||||
// for addition to a patched track.
|
// for addition to a (high-resolution) PCM track.
|
||||||
std::shared_ptr<PCMPatchedTrack> patched_track_;
|
std::shared_ptr<PCMTrack> patched_track_;
|
||||||
PCMSegment write_segment_;
|
PCMSegment write_segment_;
|
||||||
Time write_start_time_;
|
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 "PCMTrack.hpp"
|
||||||
#include "../../../NumberTheory/Factors.hpp"
|
#include "../../../NumberTheory/Factors.hpp"
|
||||||
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Storage::Disk;
|
using namespace Storage::Disk;
|
||||||
|
|
||||||
@ -54,11 +55,25 @@ PCMTrack::PCMTrack(unsigned int bits_per_track) : PCMTrack() {
|
|||||||
segment_event_sources_.emplace_back(segment);
|
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 {
|
Track *PCMTrack::clone() const {
|
||||||
return new PCMTrack(*this);
|
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.
|
// Create an empty track.
|
||||||
PCMTrack *const new_track = new PCMTrack(static_cast<unsigned int>(bits_per_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();
|
start_time += source.length();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new_track->is_resampled_clone_ = true;
|
||||||
return new_track;
|
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 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 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 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.
|
// Reset the destination.
|
||||||
std::fill(destination.data.begin() + static_cast<off_t>(start_bit), destination.data.begin() + static_cast<off_t>(end_bit), false);
|
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.
|
// 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());
|
const size_t half_offset = target_width / (2 * segment.data.size());
|
||||||
for(size_t bit = 0; bit < segment.data.size(); ++bit) {
|
for(size_t bit = 0; bit < segment.data.size(); ++bit) {
|
||||||
if(segment.data[bit]) {
|
if(segment.data[bit]) {
|
||||||
|
@ -43,6 +43,11 @@ class PCMTrack: public Track {
|
|||||||
*/
|
*/
|
||||||
PCMTrack(const PCMTrack &);
|
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
|
// as per @c Track
|
||||||
Event get_next_event() override;
|
Event get_next_event() override;
|
||||||
Time seek_to(const Time &time_since_index_hole) 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
|
// Obtains a copy of this track, flattened to a single PCMSegment, which
|
||||||
// consists of @c bits_per_track potential flux transition points.
|
// 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
|
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_;
|
std::size_t segment_pointer_;
|
||||||
|
|
||||||
PCMTrack();
|
PCMTrack();
|
||||||
|
bool is_resampled_clone_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user