mirror of
https://github.com/Serial-ATA/lofty-rs
synced 2025-03-04 14:57:17 +00:00
Merge pull request #31 from sagudev/main
This commit is contained in:
commit
b4d56ab841
12 changed files with 88 additions and 8 deletions
|
@ -36,6 +36,7 @@ fn main() {
|
|||
properties.overall_bitrate().unwrap_or(0)
|
||||
);
|
||||
println!("Sample Rate: {}", properties.sample_rate().unwrap_or(0));
|
||||
println!("Bit depth: {}", properties.bit_depth().unwrap_or(0));
|
||||
println!("Channels: {}", properties.channels().unwrap_or(0));
|
||||
println!("Duration: {}", duration_display);
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ pub struct ApeProperties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: u8,
|
||||
channels: u8,
|
||||
}
|
||||
|
||||
|
@ -25,6 +26,7 @@ impl From<ApeProperties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.sample_rate),
|
||||
bit_depth: Some(input.bit_depth),
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
@ -38,6 +40,7 @@ impl ApeProperties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: u8,
|
||||
channels: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -46,6 +49,7 @@ impl ApeProperties {
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth,
|
||||
channels,
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +74,11 @@ impl ApeProperties {
|
|||
self.sample_rate
|
||||
}
|
||||
|
||||
/// Bits per sample
|
||||
pub fn bit_depth(&self) -> u8 {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
/// Channel count
|
||||
pub fn channels(&self) -> u8 {
|
||||
self.channels
|
||||
|
@ -146,8 +155,7 @@ where
|
|||
return Err(LoftyError::Ape("File contains no frames"));
|
||||
}
|
||||
|
||||
// Unused
|
||||
let _bits_per_sample = header_read.read_u16::<LittleEndian>()?;
|
||||
let bits_per_sample = header_read.read_u16::<LittleEndian>()?;
|
||||
|
||||
let channels = header_read.read_u16::<LittleEndian>()?;
|
||||
|
||||
|
@ -174,6 +182,7 @@ where
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth: bits_per_sample as u8,
|
||||
channels: channels as u8,
|
||||
})
|
||||
}
|
||||
|
@ -202,8 +211,15 @@ where
|
|||
|
||||
let compression_level = header_first.read_u16::<LittleEndian>()?;
|
||||
|
||||
// Unused
|
||||
let _format_flags = header_first.read_u16::<LittleEndian>()?;
|
||||
let format_flags = header_first.read_u16::<LittleEndian>()?;
|
||||
// https://github.com/fernandotcl/monkeys-audio/blob/5fe956c7e67c13daa80518a4cc7001e9fa185297/src/MACLib/MACLib.h#L74
|
||||
let bit_depth = if (format_flags & 0b1) == 1 {
|
||||
8
|
||||
} else if (format_flags & 0b100) == 4 {
|
||||
24
|
||||
} else {
|
||||
16
|
||||
};
|
||||
|
||||
let blocks_per_frame = match version {
|
||||
_ if version >= 3950 => 73728 * 4,
|
||||
|
@ -245,6 +261,7 @@ where
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth,
|
||||
channels: channels as u8,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@ pub(super) fn read_properties(
|
|||
}
|
||||
|
||||
let sample_frames = comm.read_u32::<BigEndian>()?;
|
||||
let _sample_size = comm.read_u16::<BigEndian>()?;
|
||||
let sample_size = comm.read_u16::<BigEndian>()?;
|
||||
|
||||
let mut sample_rate_bytes = [0; 10];
|
||||
comm.read_exact(&mut sample_rate_bytes)?;
|
||||
|
@ -66,6 +66,7 @@ pub(super) fn read_properties(
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate: Some(sample_rate),
|
||||
bit_depth: Some(sample_size as u8),
|
||||
channels: Some(channels),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ pub struct WavProperties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: u8,
|
||||
channels: u8,
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ impl From<WavProperties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.sample_rate),
|
||||
bit_depth: Some(input.bit_depth),
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +57,7 @@ impl WavProperties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: u8,
|
||||
channels: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -63,6 +66,7 @@ impl WavProperties {
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth,
|
||||
channels,
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +91,11 @@ impl WavProperties {
|
|||
self.sample_rate
|
||||
}
|
||||
|
||||
/// Bits per sample
|
||||
pub fn bit_depth(&self) -> u8 {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
/// Channel count
|
||||
pub fn channels(&self) -> u8 {
|
||||
self.channels
|
||||
|
@ -186,6 +195,7 @@ pub(super) fn read_properties(
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth: bits_per_sample as u8,
|
||||
channels,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ impl From<Mp3Properties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.sample_rate),
|
||||
bit_depth: None,
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ pub struct Mp4Properties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: Option<u8>,
|
||||
channels: u8,
|
||||
}
|
||||
|
||||
|
@ -42,6 +43,7 @@ impl From<Mp4Properties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.sample_rate),
|
||||
bit_depth: input.bit_depth,
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +57,7 @@ impl Mp4Properties {
|
|||
overall_bitrate: u32,
|
||||
audio_bitrate: u32,
|
||||
sample_rate: u32,
|
||||
bit_depth: Option<u8>,
|
||||
channels: u8,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -63,6 +66,7 @@ impl Mp4Properties {
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth,
|
||||
channels,
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +91,11 @@ impl Mp4Properties {
|
|||
self.sample_rate
|
||||
}
|
||||
|
||||
/// Bits per sample
|
||||
pub fn bit_depth(&self) -> Option<u8> {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
/// Channel count
|
||||
pub fn channels(&self) -> u8 {
|
||||
self.channels
|
||||
|
@ -200,6 +209,7 @@ where
|
|||
overall_bitrate: 0,
|
||||
audio_bitrate: 0,
|
||||
sample_rate: 0,
|
||||
bit_depth: None,
|
||||
channels: 0,
|
||||
};
|
||||
|
||||
|
@ -335,15 +345,20 @@ where
|
|||
if alac.ident == AtomIdent::Fourcc(*b"alac") {
|
||||
properties.codec = Mp4Codec::ALAC;
|
||||
|
||||
// Skipping 13 bytes
|
||||
// Skipping 9 bytes
|
||||
// Version (4)
|
||||
// Samples per frame (4)
|
||||
// Compatible version (1)
|
||||
data.seek(SeekFrom::Current(9))?;
|
||||
|
||||
// Sample size (1)
|
||||
properties.bit_depth = Some(data.read_u8()?);
|
||||
|
||||
// Skipping 3 bytes
|
||||
// Rice history mult (1)
|
||||
// Rice initial history (1)
|
||||
// Rice parameter limit (1)
|
||||
data.seek(SeekFrom::Current(13))?;
|
||||
data.seek(SeekFrom::Current(3))?;
|
||||
|
||||
properties.channels = data.read_u8()?;
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ where
|
|||
let info = stream_info.read_u32::<BigEndian>()?;
|
||||
|
||||
let sample_rate = info >> 12;
|
||||
let bits_per_sample = ((info >> 4) & 0b11111) + 1;
|
||||
let channels = ((info >> 9) & 7) + 1;
|
||||
|
||||
// Read the remaining 32 bits of the total samples
|
||||
|
@ -54,6 +55,7 @@ where
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate: Some(sample_rate as u32),
|
||||
bit_depth: Some(bits_per_sample as u8),
|
||||
channels: Some(channels as u8),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ impl From<OpusProperties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.input_sample_rate),
|
||||
bit_depth: None,
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ impl From<VorbisProperties> for FileProperties {
|
|||
overall_bitrate: Some(input.overall_bitrate),
|
||||
audio_bitrate: Some(input.audio_bitrate),
|
||||
sample_rate: Some(input.sample_rate),
|
||||
bit_depth: None,
|
||||
channels: Some(input.channels),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ pub struct FileProperties {
|
|||
pub(crate) overall_bitrate: Option<u32>,
|
||||
pub(crate) audio_bitrate: Option<u32>,
|
||||
pub(crate) sample_rate: Option<u32>,
|
||||
pub(crate) bit_depth: Option<u8>,
|
||||
pub(crate) channels: Option<u8>,
|
||||
}
|
||||
|
||||
|
@ -17,6 +18,7 @@ impl Default for FileProperties {
|
|||
overall_bitrate: None,
|
||||
audio_bitrate: None,
|
||||
sample_rate: None,
|
||||
bit_depth: None,
|
||||
channels: None,
|
||||
}
|
||||
}
|
||||
|
@ -29,6 +31,7 @@ impl FileProperties {
|
|||
overall_bitrate: Option<u32>,
|
||||
audio_bitrate: Option<u32>,
|
||||
sample_rate: Option<u32>,
|
||||
bit_depth: Option<u8>,
|
||||
channels: Option<u8>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -36,6 +39,7 @@ impl FileProperties {
|
|||
overall_bitrate,
|
||||
audio_bitrate,
|
||||
sample_rate,
|
||||
bit_depth,
|
||||
channels,
|
||||
}
|
||||
}
|
||||
|
@ -60,6 +64,11 @@ impl FileProperties {
|
|||
self.sample_rate
|
||||
}
|
||||
|
||||
/// Bits per sample (usually 16 or 24 bit)
|
||||
pub fn bit_depth(&self) -> Option<u8> {
|
||||
self.bit_depth
|
||||
}
|
||||
|
||||
/// Channel count
|
||||
pub fn channels(&self) -> Option<u8> {
|
||||
self.channels
|
||||
|
|
BIN
tests/files/assets/b.m4a
Normal file
BIN
tests/files/assets/b.m4a
Normal file
Binary file not shown.
|
@ -13,17 +13,19 @@ const AIFF_PROPERTIES: FileProperties = FileProperties::new(
|
|||
Some(1542),
|
||||
Some(1536),
|
||||
Some(48000),
|
||||
Some(16),
|
||||
Some(2),
|
||||
);
|
||||
|
||||
const APE_PROPERTIES: ApeProperties =
|
||||
ApeProperties::new(3990, Duration::from_millis(1428), 360, 360, 48000, 2);
|
||||
ApeProperties::new(3990, Duration::from_millis(1428), 360, 360, 48000, 16, 2);
|
||||
|
||||
const FLAC_PROPERTIES: FileProperties = FileProperties::new(
|
||||
Duration::from_millis(1428),
|
||||
Some(321),
|
||||
Some(275),
|
||||
Some(48000),
|
||||
Some(16),
|
||||
Some(2),
|
||||
);
|
||||
|
||||
|
@ -44,6 +46,17 @@ const MP4_PROPERTIES: Mp4Properties = Mp4Properties::new(
|
|||
135,
|
||||
124,
|
||||
48000,
|
||||
None,
|
||||
2,
|
||||
);
|
||||
|
||||
const ALAC_PROPERTIES: Mp4Properties = Mp4Properties::new(
|
||||
Mp4Codec::ALAC,
|
||||
Duration::from_millis(1428),
|
||||
331,
|
||||
124,
|
||||
48000,
|
||||
Some(16),
|
||||
2,
|
||||
);
|
||||
|
||||
|
@ -68,6 +81,7 @@ const WAV_PROPERTIES: WavProperties = WavProperties::new(
|
|||
1542,
|
||||
1536,
|
||||
48000,
|
||||
16,
|
||||
2,
|
||||
);
|
||||
|
||||
|
@ -123,6 +137,14 @@ fn mp4_properties() {
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn alac_properties() {
|
||||
assert_eq!(
|
||||
get_properties::<Mp4File>("tests/files/assets/b.m4a").bit_depth(),
|
||||
ALAC_PROPERTIES.bit_depth()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn opus_properties() {
|
||||
assert_eq!(
|
||||
|
|
Loading…
Add table
Reference in a new issue