first draft
This commit is contained in:
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user