Add basic cue sheet handling
The cue sheet is printed to stdout.
This commit is contained in:
parent
00ed1196d6
commit
5973a06c1b
|
@ -0,0 +1,78 @@
|
||||||
|
//! Module to extract the cue sheet from the NRG metadata.
|
||||||
|
|
||||||
|
use ::error::NrgError;
|
||||||
|
use ::metadata::metadata::NrgMetadata;
|
||||||
|
|
||||||
|
|
||||||
|
pub fn write_cue_sheet(image_name: &String, nm: &NrgMetadata)
|
||||||
|
-> Result<(), NrgError> {
|
||||||
|
if nm.cuex_chunk.is_none() {
|
||||||
|
return Err(NrgError::NoNrgCue);
|
||||||
|
}
|
||||||
|
let cuex_tracks = &nm.cuex_chunk.as_ref().unwrap().tracks;
|
||||||
|
|
||||||
|
let file_name = try!(make_cue_sheet_name(image_name));
|
||||||
|
|
||||||
|
println!("FILE \"{}\" RAW", image_name);
|
||||||
|
|
||||||
|
let mut index0_pos = -1;
|
||||||
|
for track in cuex_tracks {
|
||||||
|
// Ignore lead-in and lead-out areas
|
||||||
|
if track.track_number == 0 || track.track_number == 0xAA {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore negative positions
|
||||||
|
if track.position_sectors < 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store/skip index0
|
||||||
|
if track.index_number == 0 {
|
||||||
|
index0_pos = track.position_sectors;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write track info
|
||||||
|
println!(" TRACK {:02} AUDIO", track.track_number);
|
||||||
|
|
||||||
|
// Write index0 if we stored it and it's before the current index's
|
||||||
|
// position (i.e., it indicates a pre-gap)
|
||||||
|
if index0_pos >= 0 && index0_pos < track.position_sectors {
|
||||||
|
try!(write_cue_index(0, index0_pos));
|
||||||
|
index0_pos = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write current index
|
||||||
|
try!(write_cue_index(track.index_number, track.position_sectors));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Generates the cue sheet's name from the NRG image's name.
|
||||||
|
///
|
||||||
|
/// If `image_name`'s extension is `.nrg` (case-insensitive), the cue sheet's
|
||||||
|
/// name will be the same as `image_name` with a `.cue` extension instead of
|
||||||
|
/// `.nrg`. Otherwise, the cue sheet's name will be `image_name.cue`.
|
||||||
|
fn make_cue_sheet_name(image_name: &String) -> Result<String, NrgError> {
|
||||||
|
Ok("image.cue".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn write_cue_index(index: u8, position_sectors: i32)
|
||||||
|
-> Result<(), NrgError> {
|
||||||
|
assert!(position_sectors >= 0);
|
||||||
|
|
||||||
|
// Audio CDs are played at a 75 sectors per second rate:
|
||||||
|
let mut seconds: u32 = position_sectors as u32 / 75;
|
||||||
|
let remaining_sectors = position_sectors % 75;
|
||||||
|
let minutes = seconds / 60;
|
||||||
|
seconds %= 60;
|
||||||
|
|
||||||
|
println!(" INDEX {:02} {:02}:{:02}:{:02}",
|
||||||
|
index, minutes, seconds, remaining_sectors);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ pub enum NrgError {
|
||||||
NrgFormat,
|
NrgFormat,
|
||||||
NrgFormatV1,
|
NrgFormatV1,
|
||||||
NrgChunkId,
|
NrgChunkId,
|
||||||
|
NoNrgCue,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for NrgError {
|
impl fmt::Display for NrgError {
|
||||||
|
@ -20,6 +21,7 @@ impl fmt::Display for NrgError {
|
||||||
NrgError::NrgFormat => write!(f, "NRG format unknown."),
|
NrgError::NrgFormat => write!(f, "NRG format unknown."),
|
||||||
NrgError::NrgFormatV1 => write!(f, "NRG v1 format is not handled."),
|
NrgError::NrgFormatV1 => write!(f, "NRG v1 format is not handled."),
|
||||||
NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."),
|
NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."),
|
||||||
|
NrgError::NoNrgCue => write!(f, "NRG cue sheet chunk absent."),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,6 +33,7 @@ impl Error for NrgError {
|
||||||
NrgError::NrgFormat => "NRG format",
|
NrgError::NrgFormat => "NRG format",
|
||||||
NrgError::NrgFormatV1 => "NRG format v1",
|
NrgError::NrgFormatV1 => "NRG format v1",
|
||||||
NrgError::NrgChunkId => "NRG chunk ID",
|
NrgError::NrgChunkId => "NRG chunk ID",
|
||||||
|
NrgError::NoNrgCue => "No NRG cue",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,6 +43,7 @@ impl Error for NrgError {
|
||||||
NrgError::NrgFormat => None,
|
NrgError::NrgFormat => None,
|
||||||
NrgError::NrgFormatV1 => None,
|
NrgError::NrgFormatV1 => None,
|
||||||
NrgError::NrgChunkId => None,
|
NrgError::NrgChunkId => None,
|
||||||
|
NrgError::NoNrgCue => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
//! Extracts audio data and metadata from an NRG image of an audio CD.
|
//! Extracts audio data and metadata from an NRG image of an audio CD.
|
||||||
|
|
||||||
pub mod metadata;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod metadata;
|
||||||
|
pub mod cue_sheet;
|
||||||
|
|
25
src/main.rs
25
src/main.rs
|
@ -21,7 +21,7 @@ fn main() {
|
||||||
exit_usage(&prog_name);
|
exit_usage(&prog_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
println!("NRG image name: {}", img_name);
|
println!("NRG image name: \"{}\"", img_name);
|
||||||
|
|
||||||
// We don't support more than one input file
|
// We don't support more than one input file
|
||||||
if argv.next().is_some() {
|
if argv.next().is_some() {
|
||||||
|
@ -31,18 +31,25 @@ fn main() {
|
||||||
// Open the image file
|
// Open the image file
|
||||||
let fd = File::open(&img_name);
|
let fd = File::open(&img_name);
|
||||||
if fd.is_err() {
|
if fd.is_err() {
|
||||||
println!("Can't open \"{}\": {}",
|
println!("Can't open image file \"{}\": {}",
|
||||||
img_name, fd.unwrap_err().to_string());
|
img_name, fd.unwrap_err().to_string());
|
||||||
process::exit(1);
|
process::exit(1);
|
||||||
}
|
}
|
||||||
let mut fd = fd.unwrap();
|
let mut fd = fd.unwrap();
|
||||||
|
|
||||||
// Read the image's metadata
|
// Read and display the image's metadata
|
||||||
match nrgrip::metadata::read_nrg_metadata(&mut fd) {
|
let metadata = nrgrip::metadata::read_nrg_metadata(&mut fd);
|
||||||
Err(err) => println!("Error reading \"{}\": {}",
|
if metadata.is_err() {
|
||||||
img_name, err.to_string()),
|
println!("Error reading \"{}\": {}",
|
||||||
Ok(metadata) => println!("\n\
|
img_name, metadata.unwrap_err().to_string());
|
||||||
*** Metadata ***\n\
|
process::exit(1);
|
||||||
{}", metadata),
|
}
|
||||||
|
let metadata = metadata.unwrap();
|
||||||
|
println!("\n{}", metadata);
|
||||||
|
|
||||||
|
// Read and write the cue sheet
|
||||||
|
if let Err(err) = nrgrip::cue_sheet::write_cue_sheet(&img_name, &metadata) {
|
||||||
|
println!("Error writing cue sheet: {}", err.to_string());
|
||||||
|
process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::io::{Seek, SeekFrom};
|
||||||
|
|
||||||
use ::error::NrgError;
|
use ::error::NrgError;
|
||||||
|
|
||||||
mod metadata;
|
pub mod metadata;
|
||||||
mod cuex;
|
mod cuex;
|
||||||
mod daox;
|
mod daox;
|
||||||
mod sinf;
|
mod sinf;
|
||||||
|
|
Loading…
Reference in New Issue