1use cd_da_reader::CdReader;
3
4const CD_EXTRA_TRAILING_DATA_GAP_SECTORS: u32 = 11_400;
5
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7 let reader = CdReader::open_default()?;
8 let toc = reader.read_toc()?;
9
10 println!("Table of Contents\n");
11
12 println!(
13 "Tracks {}-{} ({} total), lead-out at LBA {}\n",
14 toc.first_track,
15 toc.last_track,
16 toc.tracks.len(),
17 toc.leadout_lba,
18 );
19
20 for track in &toc.tracks {
21 let kind = if track.is_audio { "audio" } else { "data " };
22 let (m, s, f) = track.start_msf;
23 let sectors = track_end_lba(&toc, track.number) - track.start_lba;
24 let duration_secs = sectors as f64 / 75.0;
25 let mins = (duration_secs / 60.0) as u32;
26 let secs = (duration_secs % 60.0) as u32;
27
28 println!(
29 " #{:>2} {} LBA {:>6} MSF {:02}:{:02}.{:02} duration: {:02}:{:02}",
30 track.number, kind, track.start_lba, m, s, f, mins, secs,
31 );
32 }
33
34 Ok(())
35}
36
37fn track_end_lba(toc: &cd_da_reader::Toc, track_no: u8) -> u32 {
39 let idx = toc
40 .tracks
41 .iter()
42 .position(|t| t.number == track_no)
43 .unwrap();
44
45 if toc.tracks[idx].is_audio
48 && idx + 1 < toc.tracks.len()
49 && toc.tracks[idx + 1..].iter().all(|track| !track.is_audio)
50 {
51 return toc.tracks[idx + 1]
52 .start_lba
53 .saturating_sub(CD_EXTRA_TRAILING_DATA_GAP_SECTORS);
54 }
55
56 if idx + 1 < toc.tracks.len() {
57 toc.tracks[idx + 1].start_lba
58 } else {
59 toc.leadout_lba
60 }
61}