From 2e7495162841e9038b47622ba745e8830db4a2f8 Mon Sep 17 00:00:00 2001 From: Matteo Cypriani Date: Tue, 6 Dec 2016 21:10:38 -0500 Subject: [PATCH] Audio data extraction --- src/cue_sheet/mod.rs | 5 ++- src/error.rs | 8 +++++ src/lib.rs | 1 + src/main.rs | 9 ++++++ src/raw_audio.rs | 77 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 99 insertions(+), 1 deletion(-) create mode 100644 src/raw_audio.rs diff --git a/src/cue_sheet/mod.rs b/src/cue_sheet/mod.rs index 25c3dc3..7a0091b 100644 --- a/src/cue_sheet/mod.rs +++ b/src/cue_sheet/mod.rs @@ -10,7 +10,10 @@ use ::metadata::cuex::NrgCuexTrack; /// Writes the cue sheet for `image_name` into a file. /// -/// `metadata` is the metadata extracted from `image_name` by nrgrip::metadata. +/// - `image_name` is the name of the input NRG file. +/// - `metadata` is the metadata extracted from `image_name` by +/// nrgrip::metadata. +/// /// The output file's name is derived from `image_name`. pub fn write_cue_sheet(image_name: &String, metadata: &NrgMetadata) -> Result<(), NrgError> { diff --git a/src/error.rs b/src/error.rs index c16ac81..d2a51fc 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,6 +12,8 @@ pub enum NrgError { NrgFormatV1, NrgChunkId, NoNrgCue, + AudioReadError, + AudioWriteError } impl fmt::Display for NrgError { @@ -22,6 +24,8 @@ impl fmt::Display for NrgError { NrgError::NrgFormatV1 => write!(f, "NRG v1 format is not handled."), NrgError::NrgChunkId => write!(f, "NRG chunk ID unknown."), NrgError::NoNrgCue => write!(f, "NRG cue sheet chunk absent."), + NrgError::AudioReadError => write!(f, "Error reading raw audio."), + NrgError::AudioWriteError => write!(f, "Error writing raw audio."), } } } @@ -34,6 +38,8 @@ impl Error for NrgError { NrgError::NrgFormatV1 => "NRG format v1", NrgError::NrgChunkId => "NRG chunk ID", NrgError::NoNrgCue => "No NRG cue", + NrgError::AudioReadError => "Audio read error", + NrgError::AudioWriteError => "Audio write error", } } @@ -44,6 +50,8 @@ impl Error for NrgError { NrgError::NrgFormatV1 => None, NrgError::NrgChunkId => None, NrgError::NoNrgCue => None, + NrgError::AudioReadError => None, + NrgError::AudioWriteError => None, } } } diff --git a/src/lib.rs b/src/lib.rs index b19f5a1..4b8c12e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,3 +3,4 @@ pub mod error; pub mod metadata; pub mod cue_sheet; +pub mod raw_audio; diff --git a/src/main.rs b/src/main.rs index f6aaf57..1652755 100644 --- a/src/main.rs +++ b/src/main.rs @@ -48,8 +48,17 @@ fn main() { println!("\n{}", metadata); // Read and write the cue sheet + println!("\nNow extracting 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); } + + // Extract raw audio data + println!("Now extracting raw audio data..."); + if let Err(err) = nrgrip::raw_audio::extract_nrg_raw_audio( + &mut fd, &img_name, &metadata) { + println!("Error extracting raw audio data: {}", err.to_string()); + } + println!("OK!"); } diff --git a/src/raw_audio.rs b/src/raw_audio.rs new file mode 100644 index 0000000..846a87d --- /dev/null +++ b/src/raw_audio.rs @@ -0,0 +1,77 @@ +//! Module to extract the raw audio data from an NRG image file. + +use std::fs::File; +use std::io::{Seek, SeekFrom, Read, Write}; + +use ::error::NrgError; +use ::metadata::metadata::NrgMetadata; + + +/// Extracts the raw audio data from an NRG image. +/// +/// - `in_fd` is the handler to the NRG image file. +/// - `image_name` is the name of the input NRG file. +/// - `metadata` is the metadata extracted from `image_name` by +/// nrgrip::metadata. +/// +/// The output file's name is derived from `image_name`. +pub fn extract_nrg_raw_audio(in_fd: &mut File, + image_name: &String, + metadata: &NrgMetadata) + -> Result<(), NrgError> { + let skip_bytes = get_daox_track1_index1(metadata); + + try!(in_fd.seek(SeekFrom::Start(skip_bytes))); + + let file_name = make_output_file_name(image_name); + let mut out_fd = try!(File::create(file_name)); + + let mut cur_offset = skip_bytes; + while cur_offset < metadata.chunk_offset { + let mut audio_buf = [0u8; 2352]; + + let mut nbytes = try!(in_fd.read(&mut audio_buf)); + if nbytes != 2352 { + return Err(NrgError::AudioReadError); + } + cur_offset += nbytes as u64; + + nbytes = try!(out_fd.write(&audio_buf)); + if nbytes != 2352 { + return Err(NrgError::AudioWriteError); + } + } + + assert_eq!(cur_offset, metadata.chunk_offset); + Ok(()) +} + + +/// Returns the index1 of the first DAOX track in `metadata`, or 0 if there are +/// no DAOX tracks. +fn get_daox_track1_index1(metadata: &NrgMetadata) -> u64 { + if metadata.daox_chunk.is_none() { + return 0; + } + let daox_tracks = &metadata.daox_chunk.as_ref().unwrap().tracks; + if daox_tracks.is_empty() { + return 0; + } + return daox_tracks[0].index1; +} + + +/// Generates the output file's name from the NRG image's name. +/// +/// If `image_name`'s extension is `.nrg` (case-insensitive), the name will be +/// the same as `image_name` with a `.raw` extension instead of `.nrg`. +/// Otherwise, it will be `image_name.raw`. +fn make_output_file_name(image_name: &String) -> String { + let mut name = image_name.clone(); + if name.to_lowercase().ends_with(".nrg") { + let newlen = name.len() - 4; + name.truncate(newlen); + } + name.push_str(".raw"); + name +}