first draft

This commit is contained in:
tux
2026-11-03 20:19:21 +01:00
commit 158e115242
44 changed files with 10785 additions and 0 deletions
+130
View File
@@ -0,0 +1,130 @@
use cdrustanoia_core::device::image::ImageDrive;
use cdrustanoia_core::device::{bytes_to_samples, samples_to_bytes, Drive, CD_FRAMESIZE_RAW};
use cdrustanoia_core::paranoia::{Paranoia, PARANOIA_MODE_FULL};
fn make_source(sectors: usize) -> Vec<i16> {
let mut out = Vec::with_capacity(sectors * 1176);
let mut x: u64 = 0x1234_5678_9abc_def0;
for i in 0..sectors * 1176 {
x ^= x << 13;
x ^= x >> 7;
x ^= x << 17;
// Mix in some silence and a distinct waveform.
let v = if i % 5000 < 1000 {
0
} else {
(x as i16).wrapping_add((i as i16).wrapping_mul(7))
};
out.push(v);
}
out
}
#[test]
fn clean_image_roundtrip() {
let sectors = 80usize;
let source = make_source(sectors);
let bytes = samples_to_bytes(&source);
let drive = ImageDrive::from_bytes(bytes);
let mut p = Paranoia::new(Box::new(drive));
p.modeset(PARANOIA_MODE_FULL);
let mut got = Vec::with_capacity(sectors * 1176);
let mut cb = |_: i64, _: i32| {};
for _ in 0..sectors {
let sec = p.read(&mut cb).expect("read sector");
got.extend_from_slice(sec);
}
assert_eq!(got.len(), source.len());
assert_eq!(got, source);
}
#[test]
fn drive_toc_helpers() {
let bytes = vec![0u8; CD_FRAMESIZE_RAW * 10];
let drive = ImageDrive::from_bytes(bytes);
assert_eq!(drive.tracks(), 1);
assert_eq!(drive.disc_firstsector(), 0);
assert_eq!(drive.disc_lastsector(), 9);
assert_eq!(drive.track_firstsector(1), 0);
assert_eq!(drive.track_lastsector(1), 9);
let _ = bytes_to_samples(&[0, 0]);
}
fn run_config(sectors: usize, config: cdrustanoia_core::device::image::ImageConfig) -> Vec<i16> {
let source = make_source(sectors);
let bytes = samples_to_bytes(&source);
let drive = ImageDrive::with_config(bytes, config);
let mut p = Paranoia::new(Box::new(drive));
p.modeset(PARANOIA_MODE_FULL);
let start = 5usize.min(sectors);
p.seek(start as i64, 0);
let mut got = Vec::with_capacity((sectors - start) * 1176);
let mut cb = |_: i64, _: i32| {};
for _ in start..sectors {
let sec = p.read(&mut cb).expect("read sector");
got.extend_from_slice(sec);
}
let source = &source[start * 1176..];
assert_eq!(got.len(), source.len());
if got != source {
let mut best: Option<(i64, usize)> = None;
for shift in -2000i64..=2000 {
let mut bad = 0usize;
for (i, value) in got.iter().enumerate().take(source.len()) {
let j = i as i64 + shift;
if j < 0 || j as usize >= source.len() || *value != source[j as usize] {
bad += 1;
if bad > 8 {
break;
}
}
}
if bad <= 8 {
best = Some((shift, bad));
break;
}
}
if let Some((shift, bad)) = best {
panic!(
"data shifted by {} words ({} mismatches); engine did not align absolute position",
shift, bad
);
}
let idx = got
.iter()
.zip(source.iter())
.position(|(a, b)| a != b)
.unwrap_or(0);
let where0 = source.iter().position(|x| *x == got[0]);
panic!(
"mismatch at word {} (sector {} offset {}): got {} expected {}; got0 found at {:?}; got[..8]={:?} src[..8]={:?}",
idx,
idx / 1176,
idx % 1176,
got[idx],
source[idx],
where0,
&got[..got.len().min(8)],
&source[..source.len().min(8)]
);
}
got
}
#[test]
fn jittered_image_roundtrip() {
use cdrustanoia_core::device::image::{ImageConfig, ImageFaults};
let sectors = 20usize;
let config = ImageConfig {
tracks: vec![(0, sectors as i64 - 1, 0)],
faults: ImageFaults {
jitter_words: 180,
jitter_period: 1,
jitter_skip: 10,
max_read_sectors: 0,
..Default::default()
},
..Default::default()
};
run_config(sectors, config);
}