use crate::flac::ChannelAssignment;
use crate::flac::bitstream::{BitReader, BitWriter};
use crate::flac::constants::{
BITS_PER_SAMPLE_TABLE, BLOCK_SIZE_TABLE, FRAME_SYNC_CODE, SAMPLE_RATE_TABLE,
bits_per_sample_to_code, block_size_to_code, sample_rate_to_code,
};
use crate::flac::crc::{Crc8, Crc16};
use crate::flac::error::FlacError;
use crate::flac::subframe::{Subframe, decode_subframe, decode_subframe_into};
#[cfg(not(feature = "flac-parallel"))]
use crate::flac::subframe::encode_subframe_into;
#[cfg(feature = "flac-parallel")]
use crate::flac::subframe::{EncodedSubframe, encode_subframe};
#[derive(Debug, Clone, Copy)]
pub struct FrameHeader {
pub variable_blocksize: bool,
pub block_size: u32,
pub sample_rate: u32,
pub channel_assignment: ChannelAssignment,
pub bits_per_sample: u8,
pub frame_or_sample_number: u64,
}
#[derive(Debug)]
pub struct Frame {
pub header: FrameHeader,
pub subframes: Vec<Subframe>,
}
impl Frame {
pub fn into_channel_samples(self) -> Vec<Vec<i32>> {
let block_size = self.subframes.first().map(|s| s.samples.len()).unwrap_or(0);
match self.header.channel_assignment {
ChannelAssignment::LeftSide => {
let mut iter = self.subframes.into_iter();
let left = iter.next().map(|s| s.samples).unwrap_or_default();
let side = iter.next().map(|s| s.samples).unwrap_or_default();
let right: Vec<i32> = left.iter().zip(side.iter()).map(|(&l, &s)| l - s).collect();
vec![left, right]
}
ChannelAssignment::RightSide => {
let mut iter = self.subframes.into_iter();
let side = iter.next().map(|s| s.samples).unwrap_or_default();
let right = iter.next().map(|s| s.samples).unwrap_or_default();
let left: Vec<i32> = side
.iter()
.zip(right.iter())
.map(|(&s, &r)| s + r)
.collect();
vec![left, right]
}
ChannelAssignment::MidSide => {
let mut iter = self.subframes.into_iter();
let mid = iter.next().map(|s| s.samples).unwrap_or_default();
let side = iter.next().map(|s| s.samples).unwrap_or_default();
let mut left = Vec::with_capacity(block_size);
let mut right = Vec::with_capacity(block_size);
for (&m, &s) in mid.iter().zip(side.iter()) {
let l = m + (s >> 1) + (s & 1);
let r = l - s;
left.push(l);
right.push(r);
}
vec![left, right]
}
ChannelAssignment::Independent(_) => {
self.subframes.into_iter().map(|sf| sf.samples).collect()
}
}
}
pub fn block_size(&self) -> usize {
self.subframes.first().map(|s| s.samples.len()).unwrap_or(0)
}
pub const fn num_channels(&self) -> usize {
self.subframes.len()
}
}
pub fn decode_frame(
data: &[u8],
streaminfo_sample_rate: u32,
streaminfo_bits_per_sample: u8,
_streaminfo_channels: u8,
) -> Result<(Frame, usize), FlacError> {
if data.len() < 6 {
return Err(FlacError::UnexpectedEof);
}
let mut reader = BitReader::new(data);
let sync = reader.read_bits(14)? as u16;
if sync != FRAME_SYNC_CODE {
return Err(FlacError::invalid_frame_sync(sync));
}
let reserved = reader.read_bit()?;
if reserved {
return Err(FlacError::InvalidFrameSync { found: 0xFFFF });
}
let variable_blocksize = reader.read_bit()?;
let block_size_code = reader.read_bits(4)? as u8;
let sample_rate_code = reader.read_bits(4)? as u8;
let channel_code = reader.read_bits(4)? as u8;
let sample_size_code = reader.read_bits(3)? as u8;
let reserved2 = reader.read_bit()?;
if reserved2 {
return Err(FlacError::ReservedBitsPerSampleCode);
}
let channel_assignment = ChannelAssignment::from_code(channel_code)
.ok_or(FlacError::InvalidChannelAssignment(channel_code))?;
let bits_per_sample = if sample_size_code == 0 {
streaminfo_bits_per_sample
} else if sample_size_code == 0b011 {
return Err(FlacError::ReservedBitsPerSampleCode);
} else {
BITS_PER_SAMPLE_TABLE[sample_size_code as usize]
};
let frame_or_sample_number = reader.read_utf8_coded()?;
let block_size = match block_size_code {
0b0000 => return Err(FlacError::ReservedBlockSizeCode),
0b0110 => reader.read_bits(8)? + 1,
0b0111 => reader.read_bits(16)? + 1,
_ => BLOCK_SIZE_TABLE[block_size_code as usize],
};
let sample_rate = match sample_rate_code {
0b0000 => streaminfo_sample_rate,
0b1100 => reader.read_bits(8)? * 1000,
0b1101 => reader.read_bits(16)?,
0b1110 => reader.read_bits(16)? * 10,
0b1111 => return Err(FlacError::ReservedSampleRateCode),
_ => SAMPLE_RATE_TABLE[sample_rate_code as usize],
};
let crc8_header_len = reader.byte_position();
let crc8_expected = reader.read_bits(8)? as u8;
let crc8_computed = Crc8::compute(&data[..crc8_header_len]);
if crc8_computed != crc8_expected {
return Err(FlacError::FrameHeaderCrcMismatch { expected: crc8_expected, computed: crc8_computed });
}
let header = FrameHeader {
variable_blocksize,
block_size,
sample_rate,
channel_assignment,
bits_per_sample,
frame_or_sample_number,
};
let num_channels = channel_assignment.channels() as usize;
let mut subframes = Vec::with_capacity(num_channels);
for ch in 0..num_channels {
let subframe_bps = match (channel_assignment, ch) {
(ChannelAssignment::MidSide, 1)|(ChannelAssignment::RightSide, 0)| (ChannelAssignment::LeftSide, 1) => bits_per_sample + 1,
_ => bits_per_sample,
};
let subframe = decode_subframe(&mut reader, block_size as usize, subframe_bps)?;
subframes.push(subframe);
}
reader.align_to_byte();
let crc16_frame_len = reader.byte_position();
let crc16_expected = reader.read_bits(16)? as u16;
let bytes_consumed = reader.byte_position();
let crc16_computed = Crc16::compute(&data[..crc16_frame_len]);
if crc16_computed != crc16_expected {
return Err(FlacError::FrameCrcMismatch { expected: crc16_expected, computed: crc16_computed });
}
Ok((Frame { header, subframes }, bytes_consumed))
}
pub(crate) fn decode_frame_into_channels(
data: &[u8],
streaminfo_sample_rate: u32,
streaminfo_bits_per_sample: u8,
_streaminfo_channels: u8,
out_channels: &mut [Vec<i32>],
scratch: &mut (Vec<i32>, Vec<i32>),
) -> Result<usize, FlacError> {
if data.len() < 6 {
return Err(FlacError::UnexpectedEof);
}
let mut reader = BitReader::new(data);
let sync = reader.read_bits(14)? as u16;
if sync != FRAME_SYNC_CODE {
return Err(FlacError::invalid_frame_sync(sync));
}
let reserved = reader.read_bit()?;
if reserved {
return Err(FlacError::InvalidFrameSync { found: 0xFFFF });
}
let _variable_blocksize = reader.read_bit()?;
let block_size_code = reader.read_bits(4)? as u8;
let sample_rate_code = reader.read_bits(4)? as u8;
let channel_code = reader.read_bits(4)? as u8;
let sample_size_code = reader.read_bits(3)? as u8;
let reserved2 = reader.read_bit()?;
if reserved2 {
return Err(FlacError::ReservedBitsPerSampleCode);
}
let channel_assignment = ChannelAssignment::from_code(channel_code)
.ok_or(FlacError::InvalidChannelAssignment(channel_code))?;
let bits_per_sample = if sample_size_code == 0 {
streaminfo_bits_per_sample
} else if sample_size_code == 0b011 {
return Err(FlacError::ReservedBitsPerSampleCode);
} else {
BITS_PER_SAMPLE_TABLE[sample_size_code as usize]
};
let _frame_or_sample_number = reader.read_utf8_coded()?;
let block_size = match block_size_code {
0b0000 => return Err(FlacError::ReservedBlockSizeCode),
0b0110 => reader.read_bits(8)? + 1,
0b0111 => reader.read_bits(16)? + 1,
_ => BLOCK_SIZE_TABLE[block_size_code as usize],
} as usize;
let _sample_rate = match sample_rate_code {
0b0000 => streaminfo_sample_rate,
0b1100 => reader.read_bits(8)? * 1000,
0b1101 => reader.read_bits(16)?,
0b1110 => reader.read_bits(16)? * 10,
0b1111 => return Err(FlacError::ReservedSampleRateCode),
_ => SAMPLE_RATE_TABLE[sample_rate_code as usize],
};
let crc8_header_len = reader.byte_position();
let crc8_expected = reader.read_bits(8)? as u8;
let crc8_computed = Crc8::compute(&data[..crc8_header_len]);
if crc8_computed != crc8_expected {
return Err(FlacError::FrameHeaderCrcMismatch {
expected: crc8_expected,
computed: crc8_computed,
});
}
let num_channels = channel_assignment.channels() as usize;
match channel_assignment {
ChannelAssignment::Independent(_) => {
for ch in out_channels.iter_mut().take(num_channels) {
decode_subframe_into(&mut reader, block_size, bits_per_sample, ch)?;
}
}
ChannelAssignment::LeftSide => {
scratch.0.clear();
scratch.1.clear();
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch.0)?;
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch.1)?;
for (s, &l) in scratch.1.iter_mut().zip(scratch.0.iter()) {
*s = l - *s;
}
let (a, b) = out_channels.split_at_mut(1);
a[0].extend_from_slice(&scratch.0);
b[0].extend_from_slice(&scratch.1);
}
ChannelAssignment::RightSide => {
scratch.0.clear();
scratch.1.clear();
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch.0)?;
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch.1)?;
for (s, &r) in scratch.0.iter_mut().zip(scratch.1.iter()) {
*s += r;
}
let (a, b) = out_channels.split_at_mut(1);
a[0].extend_from_slice(&scratch.0);
b[0].extend_from_slice(&scratch.1);
}
ChannelAssignment::MidSide => {
scratch.0.clear();
scratch.1.clear();
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch.0)?;
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch.1)?;
for (m, s) in scratch.0.iter_mut().zip(scratch.1.iter_mut()) {
let mid = (*m << 1) | (*s & 1);
let side = *s;
*m = (mid + side) >> 1;
*s = (mid - side) >> 1;
}
let (a, b) = out_channels.split_at_mut(1);
a[0].extend_from_slice(&scratch.0);
b[0].extend_from_slice(&scratch.1);
}
}
reader.align_to_byte();
let crc16_frame_len = reader.byte_position();
let crc16_expected = reader.read_bits(16)? as u16;
let bytes_consumed = reader.byte_position();
let crc16_computed = Crc16::compute(&data[..crc16_frame_len]);
if crc16_computed != crc16_expected {
return Err(FlacError::FrameCrcMismatch {
expected: crc16_expected,
computed: crc16_computed,
});
}
Ok(bytes_consumed)
}
pub(crate) fn decode_frame_into_scratch(
data: &[u8],
streaminfo_sample_rate: u32,
streaminfo_bits_per_sample: u8,
scratch: &mut [Vec<i32>],
) -> Result<usize, FlacError> {
if data.len() < 6 {
return Err(FlacError::UnexpectedEof);
}
let mut reader = BitReader::new(data);
let sync = reader.read_bits(14)? as u16;
if sync != FRAME_SYNC_CODE {
return Err(FlacError::invalid_frame_sync(sync));
}
let reserved = reader.read_bit()?;
if reserved {
return Err(FlacError::InvalidFrameSync { found: 0xFFFF });
}
let _variable_blocksize = reader.read_bit()?;
let block_size_code = reader.read_bits(4)? as u8;
let sample_rate_code = reader.read_bits(4)? as u8;
let channel_code = reader.read_bits(4)? as u8;
let sample_size_code = reader.read_bits(3)? as u8;
let reserved2 = reader.read_bit()?;
if reserved2 {
return Err(FlacError::ReservedBitsPerSampleCode);
}
let channel_assignment = ChannelAssignment::from_code(channel_code)
.ok_or(FlacError::InvalidChannelAssignment(channel_code))?;
let bits_per_sample = if sample_size_code == 0 {
streaminfo_bits_per_sample
} else if sample_size_code == 0b011 {
return Err(FlacError::ReservedBitsPerSampleCode);
} else {
BITS_PER_SAMPLE_TABLE[sample_size_code as usize]
};
let _frame_or_sample_number = reader.read_utf8_coded()?;
let block_size = match block_size_code {
0b0000 => return Err(FlacError::ReservedBlockSizeCode),
0b0110 => reader.read_bits(8)? + 1,
0b0111 => reader.read_bits(16)? + 1,
_ => BLOCK_SIZE_TABLE[block_size_code as usize],
} as usize;
let _sample_rate = match sample_rate_code {
0b0000 => streaminfo_sample_rate,
0b1100 => reader.read_bits(8)? * 1000,
0b1101 => reader.read_bits(16)?,
0b1110 => reader.read_bits(16)? * 10,
0b1111 => return Err(FlacError::ReservedSampleRateCode),
_ => SAMPLE_RATE_TABLE[sample_rate_code as usize],
};
let crc8_header_len = reader.byte_position();
let crc8_expected = reader.read_bits(8)? as u8;
let crc8_computed = Crc8::compute(&data[..crc8_header_len]);
if crc8_computed != crc8_expected {
return Err(FlacError::FrameHeaderCrcMismatch {
expected: crc8_expected,
computed: crc8_computed,
});
}
let num_channels = channel_assignment.channels() as usize;
for ch in scratch[..num_channels].iter_mut() {
ch.clear();
}
match channel_assignment {
ChannelAssignment::Independent(_) => {
for ch in scratch.iter_mut().take(num_channels) {
decode_subframe_into(&mut reader, block_size, bits_per_sample, ch)?;
}
}
ChannelAssignment::LeftSide => {
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch[0])?;
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch[1])?;
let (left, rest) = scratch.split_at_mut(1);
for (s, &l) in rest[0].iter_mut().zip(left[0].iter()) {
*s = l - *s;
}
}
ChannelAssignment::RightSide => {
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch[0])?;
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch[1])?;
let (side, rest) = scratch.split_at_mut(1);
for (s, &r) in side[0].iter_mut().zip(rest[0].iter()) {
*s += r;
}
}
ChannelAssignment::MidSide => {
decode_subframe_into(&mut reader, block_size, bits_per_sample, &mut scratch[0])?;
decode_subframe_into(&mut reader, block_size, bits_per_sample + 1, &mut scratch[1])?;
let (mid_slice, side_slice) = scratch.split_at_mut(1);
for (m, s) in mid_slice[0].iter_mut().zip(side_slice[0].iter_mut()) {
let mid = (*m << 1) | (*s & 1);
let side = *s;
*m = (mid + side) >> 1;
*s = (mid - side) >> 1;
}
}
}
reader.align_to_byte();
let crc16_frame_len = reader.byte_position();
let crc16_expected = reader.read_bits(16)? as u16;
let bytes_consumed = reader.byte_position();
let crc16_computed = Crc16::compute(&data[..crc16_frame_len]);
if crc16_computed != crc16_expected {
return Err(FlacError::FrameCrcMismatch {
expected: crc16_expected,
computed: crc16_computed,
});
}
Ok(bytes_consumed)
}
pub fn encode_frame(
samples: &[i32],
channels: u8,
block_size: u32,
sample_rate: u32,
bits_per_sample: u8,
frame_number: u64,
max_lpc_order: usize,
qlp_precision: u8,
min_partition_order: u8,
max_partition_order: u8,
try_mid_side: bool,
exhaustive_rice: bool,
) -> Result<Vec<u8>, FlacError> {
let num_channels = channels as usize;
let samples_per_channel = block_size as usize;
let mut ch_vecs: Vec<Vec<i32>> = vec![Vec::with_capacity(samples_per_channel); num_channels];
for (i, &sample) in samples.iter().enumerate() {
ch_vecs[i % num_channels].push(sample);
}
let ch_slices: Vec<&[i32]> = ch_vecs.iter().map(|v| v.as_slice()).collect();
encode_frame_from_channels(
&ch_slices,
bits_per_sample,
sample_rate,
frame_number,
max_lpc_order,
qlp_precision,
min_partition_order,
max_partition_order,
try_mid_side,
exhaustive_rice,
)
}
fn encode_frame_header(
writer: &mut BitWriter,
block_size: u32,
sample_rate: u32,
channel_assignment: ChannelAssignment,
bits_per_sample: u8,
frame_number: u64,
) -> Result<(), FlacError> {
writer.write_bits(FRAME_SYNC_CODE as u32, 14);
writer.write_bit(false);
writer.write_bit(false);
let (bs_code, bs_extra) = block_size_to_code(block_size);
writer.write_bits(bs_code as u32, 4);
let (sr_code, sr_extra) = sample_rate_to_code(sample_rate);
writer.write_bits(sr_code as u32, 4);
writer.write_bits(channel_assignment.code() as u32, 4);
let bps_code = bits_per_sample_to_code(bits_per_sample).unwrap_or(0);
writer.write_bits(bps_code as u32, 3);
writer.write_bit(false);
writer.write_utf8_coded(frame_number);
match bs_extra {
1 => writer.write_bits((block_size - 1) as u32, 8),
2 => writer.write_bits((block_size - 1) as u32, 16),
_ => {}
}
match sr_extra {
1 => writer.write_bits(sample_rate / 1000, 8),
2 => writer.write_bits(sample_rate, 16),
3 => writer.write_bits(sample_rate / 10, 16),
_ => {}
}
Ok(())
}
fn find_best_stereo_mode(
left: &[i32],
right: &[i32],
) -> (ChannelAssignment, Vec<Vec<i32>>) {
let n = left.len() as u64;
let side: Vec<i32> = left.iter().zip(right.iter()).map(|(&l, &r)| l - r).collect();
let mid: Vec<i32> = left.iter().zip(right.iter()).map(|(&l, &r)| (l + r) >> 1).collect();
let e_left: u64 = left.iter().map(|&s| (s as i64).unsigned_abs()).sum();
let e_right: u64 = right.iter().map(|&s| (s as i64).unsigned_abs()).sum();
let e_side: u64 = side.iter().map(|&s| (s as i64).unsigned_abs()).sum();
let e_mid: u64 = mid.iter().map(|&s| (s as i64).unsigned_abs()).sum();
let score_ind = e_left + e_right;
let score_ls = e_left + e_side + n;
let score_rs = e_side + e_right + n;
let score_ms = e_mid + e_side + n;
if score_ind <= score_ls && score_ind <= score_rs && score_ind <= score_ms {
(ChannelAssignment::Independent(2), vec![left.to_vec(), right.to_vec()])
} else if score_ls <= score_rs && score_ls <= score_ms {
(ChannelAssignment::LeftSide, vec![left.to_vec(), side])
} else if score_rs <= score_ms {
(ChannelAssignment::RightSide, vec![side, right.to_vec()])
} else {
(ChannelAssignment::MidSide, vec![mid, side])
}
}
pub fn encode_frame_from_channels(
channel_samples: &[&[i32]],
bits_per_sample: u8,
sample_rate: u32,
frame_number: u64,
max_lpc_order: usize,
qlp_precision: u8,
min_partition_order: u8,
max_partition_order: u8,
try_mid_side: bool,
exhaustive_rice: bool,
) -> Result<Vec<u8>, FlacError> {
let num_channels = channel_samples.len() as u8;
if channel_samples.is_empty() {
return Err(FlacError::InvalidChannelCount { channels: 0 });
}
let block_size = channel_samples[0].len() as u32;
let mut writer =
BitWriter::with_capacity(channel_samples[0].len() * num_channels as usize * 4);
if num_channels == 2 && try_mid_side {
let (channel_assignment, owned) =
find_best_stereo_mode(channel_samples[0], channel_samples[1]);
encode_frame_header(&mut writer, block_size, sample_rate, channel_assignment,
bits_per_sample, frame_number)?;
writer.align_to_byte();
let crc8 = Crc8::compute(writer.data());
writer.write_bits(crc8 as u32, 8);
#[cfg(feature = "flac-parallel")]
{
use rayon::prelude::*;
let subframe_data: Vec<EncodedSubframe> = owned
.par_iter()
.enumerate()
.map(|(ch, ch_data)| {
let subframe_bps = match (channel_assignment, ch) {
(ChannelAssignment::LeftSide, 1)
| (ChannelAssignment::RightSide, 0)
| (ChannelAssignment::MidSide, 1) => bits_per_sample + 1,
_ => bits_per_sample,
};
encode_subframe(ch_data, subframe_bps, max_lpc_order, qlp_precision,
min_partition_order, max_partition_order, exhaustive_rice)
})
.collect::<Result<Vec<_>, _>>()?;
for encoded in &subframe_data {
writer.write_packed_bits(&encoded.data, encoded.bits);
}
}
#[cfg(not(feature = "flac-parallel"))]
for (ch, ch_data) in owned.iter().enumerate() {
let subframe_bps = match (channel_assignment, ch) {
(ChannelAssignment::LeftSide, 1)
| (ChannelAssignment::RightSide, 0)
| (ChannelAssignment::MidSide, 1) => bits_per_sample + 1,
_ => bits_per_sample,
};
encode_subframe_into(&mut writer, ch_data, subframe_bps, max_lpc_order,
qlp_precision, min_partition_order, max_partition_order, exhaustive_rice)?;
}
} else {
let channel_assignment = ChannelAssignment::Independent(num_channels);
encode_frame_header(&mut writer, block_size, sample_rate, channel_assignment,
bits_per_sample, frame_number)?;
writer.align_to_byte();
let crc8 = Crc8::compute(writer.data());
writer.write_bits(crc8 as u32, 8);
#[cfg(feature = "flac-parallel")]
{
use rayon::prelude::*;
let subframe_data: Vec<EncodedSubframe> = channel_samples
.par_iter()
.map(|&ch_data| {
encode_subframe(ch_data, bits_per_sample, max_lpc_order, qlp_precision,
min_partition_order, max_partition_order, exhaustive_rice)
})
.collect::<Result<Vec<_>, _>>()?;
for encoded in &subframe_data {
writer.write_packed_bits(&encoded.data, encoded.bits);
}
}
#[cfg(not(feature = "flac-parallel"))]
for &ch_data in channel_samples {
encode_subframe_into(&mut writer, ch_data, bits_per_sample, max_lpc_order,
qlp_precision, min_partition_order, max_partition_order, exhaustive_rice)?;
}
}
writer.align_to_byte();
let frame_data = writer.data();
let crc16 = Crc16::compute(frame_data);
writer.write_bits(crc16 as u32, 16);
Ok(writer.finish())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_channel_assignment_code_roundtrip() {
let assignments = [
ChannelAssignment::Independent(1),
ChannelAssignment::Independent(2),
ChannelAssignment::Independent(8),
ChannelAssignment::LeftSide,
ChannelAssignment::RightSide,
ChannelAssignment::MidSide,
];
for assignment in assignments {
let code = assignment.code();
let parsed = ChannelAssignment::from_code(code);
assert!(
parsed.is_some(),
"Failed to parse code for {:?}",
assignment
);
assert_eq!(parsed.unwrap().channels(), assignment.channels());
}
}
#[test]
fn test_stereo_decorrelation_roundtrip() {
let left: Vec<i32> = (0..100).map(|i| (i * 100) as i32).collect();
let right: Vec<i32> = (0..100).map(|i| (i * 50 + 25) as i32).collect();
let mut interleaved = Vec::with_capacity(200);
for i in 0..100 {
interleaved.push(left[i]);
interleaved.push(right[i]);
}
let frame = Frame {
header: FrameHeader {
variable_blocksize: false,
block_size: 100,
sample_rate: 44100,
channel_assignment: ChannelAssignment::Independent(2),
bits_per_sample: 16,
frame_or_sample_number: 0,
},
subframes: vec![
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: left.clone(),
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: right.clone(),
},
],
};
let decoded = frame.into_channel_samples();
assert_eq!(decoded.len(), 2);
assert_eq!(decoded[0], left);
assert_eq!(decoded[1], right);
}
#[test]
fn test_mid_side_decorrelation() {
let left = vec![100i32, 200, 300];
let right = vec![50i32, 150, 250];
let mid: Vec<i32> = left
.iter()
.zip(&right)
.map(|(&l, &r)| (l + r) >> 1)
.collect();
let side: Vec<i32> = left.iter().zip(&right).map(|(&l, &r)| l - r).collect();
let frame = Frame {
header: FrameHeader {
variable_blocksize: false,
block_size: 3,
sample_rate: 44100,
channel_assignment: ChannelAssignment::MidSide,
bits_per_sample: 16,
frame_or_sample_number: 0,
},
subframes: vec![
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: mid,
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: side,
},
],
};
let decoded = frame.into_channel_samples();
assert_eq!(decoded.len(), 2);
assert_eq!(decoded[0], left);
assert_eq!(decoded[1], right);
}
#[test]
fn test_encode_decode_frame_mono_constant() {
let block_size = 512u32;
let samples: Vec<i32> = vec![0i32; block_size as usize];
let frame_bytes = encode_frame(
&samples,
1, block_size,
44100,
16,
0, 0, 12, 0, 3, false, false, )
.expect("encode_frame should succeed");
assert!(!frame_bytes.is_empty(), "encoded frame must not be empty");
let (frame, bytes_consumed) =
decode_frame(&frame_bytes, 44100, 16, 1).expect("decode_frame should succeed");
assert_eq!(bytes_consumed, frame_bytes.len(), "all bytes consumed");
assert_eq!(frame.block_size(), block_size as usize, "block size");
assert_eq!(frame.num_channels(), 1, "channels");
let channels = frame.into_channel_samples();
assert_eq!(channels.len(), 1);
assert_eq!(channels[0].len(), block_size as usize);
assert!(channels[0].iter().all(|&s| s == 0), "silence should decode to zeros");
}
#[test]
fn test_encode_decode_frame_mono_dc() {
let block_size = 1024u32;
let dc_value = 1000i32;
let samples: Vec<i32> = vec![dc_value; block_size as usize];
let frame_bytes = encode_frame(
&samples, 1, block_size, 44100, 16, 0, 0, 12, 0, 3, false, false,
)
.expect("encode");
let (frame, _) = decode_frame(&frame_bytes, 44100, 16, 1).expect("decode");
let channels = frame.into_channel_samples();
assert_eq!(channels[0].len(), block_size as usize);
assert!(
channels[0].iter().all(|&s| s == dc_value),
"DC signal should decode exactly"
);
}
#[test]
fn test_encode_decode_frame_large_block() {
let block_size = 4096u32;
let samples: Vec<i32> = vec![0i32; block_size as usize];
let frame_bytes = encode_frame(
&samples, 1, block_size, 48000, 16, 5, 0, 12, 0, 4, false, false,
)
.expect("encode large block");
let (frame, consumed) = decode_frame(&frame_bytes, 48000, 16, 1).expect("decode large block");
assert_eq!(consumed, frame_bytes.len());
assert_eq!(frame.block_size(), block_size as usize);
}
#[test]
fn test_encode_decode_frame_number() {
let block_size = 1024u32;
let samples: Vec<i32> = vec![0i32; block_size as usize];
for frame_number in [0u64, 1, 127, 128, 0x3FFF, 0x1FFFFF] {
let frame_bytes = encode_frame(
&samples, 1, block_size, 44100, 16, frame_number, 0, 12, 0, 3, false, false,
)
.unwrap_or_else(|e| panic!("encode frame {frame_number}: {e}"));
let (frame, _) = decode_frame(&frame_bytes, 44100, 16, 1)
.unwrap_or_else(|e| panic!("decode frame {frame_number}: {e}"));
assert_eq!(
frame.header.frame_or_sample_number, frame_number,
"frame number should match"
);
}
}
#[test]
fn test_encode_decode_various_sample_rates() {
let block_size = 512u32;
let samples: Vec<i32> = vec![0i32; block_size as usize];
for sr in [44100u32, 48000, 96000] {
let frame_bytes = encode_frame(
&samples, 1, block_size, sr, 16, 0, 0, 12, 0, 3, false, false,
)
.unwrap_or_else(|e| panic!("encode sr={sr}: {e}"));
let (frame, _) = decode_frame(&frame_bytes, sr, 16, 1)
.unwrap_or_else(|e| panic!("decode sr={sr}: {e}"));
assert_eq!(frame.header.sample_rate, sr, "sample rate should be preserved");
}
}
#[test]
fn test_left_side_decorrelation_roundtrip() {
let left: Vec<i32> = (0..100).map(|i| i as i32 * 10).collect();
let right: Vec<i32> = (0..100).map(|i| i as i32 * 10 + 5).collect();
let side: Vec<i32> = left.iter().zip(&right).map(|(&l, &r)| l - r).collect();
let frame = Frame {
header: FrameHeader {
variable_blocksize: false,
block_size: 100,
sample_rate: 44100,
channel_assignment: ChannelAssignment::LeftSide,
bits_per_sample: 16,
frame_or_sample_number: 0,
},
subframes: vec![
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: left.clone(),
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: side,
},
],
};
let decoded = frame.into_channel_samples();
assert_eq!(decoded[0], left, "left channel should match");
assert_eq!(decoded[1], right, "right channel should be restored");
}
#[test]
fn test_right_side_decorrelation_roundtrip() {
let left: Vec<i32> = (0..50).map(|i| i as i32 * 20).collect();
let right: Vec<i32> = (0..50).map(|i| i as i32 * 20 + 10).collect();
let side: Vec<i32> = left.iter().zip(&right).map(|(&l, &r)| l - r).collect();
let frame = Frame {
header: FrameHeader {
variable_blocksize: false,
block_size: 50,
sample_rate: 44100,
channel_assignment: ChannelAssignment::RightSide,
bits_per_sample: 16,
frame_or_sample_number: 0,
},
subframes: vec![
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: side,
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Verbatim,
wasted_bits: 0,
samples: right.clone(),
},
],
};
let decoded = frame.into_channel_samples();
assert_eq!(decoded[0], left, "left channel");
assert_eq!(decoded[1], right, "right channel");
}
#[test]
fn test_frame_accessors() {
let frame = Frame {
header: FrameHeader {
variable_blocksize: false,
block_size: 256,
sample_rate: 44100,
channel_assignment: ChannelAssignment::Independent(3),
bits_per_sample: 16,
frame_or_sample_number: 42,
},
subframes: vec![
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Constant,
wasted_bits: 0,
samples: vec![0i32; 256],
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Constant,
wasted_bits: 0,
samples: vec![0i32; 256],
},
Subframe {
subframe_type: crate::flac::subframe::SubframeType::Constant,
wasted_bits: 0,
samples: vec![0i32; 256],
},
],
};
assert_eq!(frame.block_size(), 256);
assert_eq!(frame.num_channels(), 3);
}
}