use crate::bitwriter::BitWriter;
use crate::format::*;
use crate::rice::RicePartition;
fn write_subframe_header(bw: &mut BitWriter, type_bits: u32, wasted_bits: u32) {
bw.write_raw_u32(type_bits | u32::from(wasted_bits > 0), SUBFRAME_HEADER_LEN);
if wasted_bits > 0 {
bw.write_unary_unsigned(wasted_bits - 1);
}
}
pub fn write_constant(bw: &mut BitWriter, value: i64, subframe_bps: u32, wasted_bits: u32) {
write_subframe_header(bw, SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK, wasted_bits);
bw.write_raw_i64(value, subframe_bps);
}
pub fn write_verbatim(bw: &mut BitWriter, signal: &[i64], subframe_bps: u32, wasted_bits: u32) {
write_subframe_header(bw, SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK, wasted_bits);
for &s in signal {
bw.write_raw_i64(s, subframe_bps);
}
}
pub fn constant_bits(subframe_bps: u32, wasted_bits: u32) -> u32 {
SUBFRAME_HEADER_LEN + wasted_bits + subframe_bps
}
pub fn verbatim_bits(blocksize: u32, subframe_bps: u32, wasted_bits: u32) -> u32 {
SUBFRAME_HEADER_LEN + wasted_bits + blocksize * subframe_bps
}
pub fn write_fixed(
bw: &mut BitWriter,
order: u32,
warmup: &[i64],
subframe_bps: u32,
wasted_bits: u32,
residual: &[i32],
rice: &RicePartition,
) {
write_subframe_header(
bw,
SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK | (order << 1),
wasted_bits,
);
for &w in warmup {
bw.write_raw_i64(w, subframe_bps);
}
write_entropy_and_residual(bw, residual, order, rice);
}
pub fn fixed_bits(order: u32, subframe_bps: u32, wasted_bits: u32, residual_bits: u32) -> u32 {
let header = SUBFRAME_HEADER_LEN + wasted_bits + order * subframe_bps;
if residual_bits < u32::MAX - header {
header + residual_bits
} else {
u32::MAX
}
}
#[allow(clippy::too_many_arguments)]
pub fn write_lpc(
bw: &mut BitWriter,
order: u32,
warmup: &[i64],
qlp_coeff: &[i32],
precision: u32,
shift: i32,
subframe_bps: u32,
wasted_bits: u32,
residual: &[i32],
rice: &RicePartition,
) {
write_subframe_header(
bw,
SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK | ((order - 1) << 1),
wasted_bits,
);
for &w in warmup {
bw.write_raw_i64(w, subframe_bps);
}
bw.write_raw_u32(precision - 1, SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN);
bw.write_raw_i32(shift, SUBFRAME_LPC_QLP_SHIFT_LEN);
for &c in qlp_coeff {
bw.write_raw_i32(c, precision);
}
write_entropy_and_residual(bw, residual, order, rice);
}
fn write_entropy_and_residual(
bw: &mut BitWriter,
residual: &[i32],
predictor_order: u32,
rice: &RicePartition,
) {
let method_type = if rice.is_rice2 {
ENTROPY_CODING_METHOD_PARTITIONED_RICE2
} else {
ENTROPY_CODING_METHOD_PARTITIONED_RICE
};
bw.write_raw_u32(method_type, ENTROPY_CODING_METHOD_TYPE_LEN);
bw.write_raw_u32(rice.order, ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN);
write_residual_partitioned_rice(
bw,
residual,
predictor_order,
&rice.parameters,
rice.order,
rice.is_rice2,
);
}
pub fn lpc_bits(
order: u32,
precision: u32,
subframe_bps: u32,
wasted_bits: u32,
residual_bits: u32,
) -> u32 {
let header = SUBFRAME_HEADER_LEN
+ wasted_bits
+ SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN
+ SUBFRAME_LPC_QLP_SHIFT_LEN
+ order * (precision + subframe_bps);
if residual_bits < u32::MAX - header {
header + residual_bits
} else {
u32::MAX
}
}
fn write_residual_partitioned_rice(
bw: &mut BitWriter,
residual: &[i32],
predictor_order: u32,
parameters: &[u32],
partition_order: u32,
is_rice2: bool,
) {
let plen = if is_rice2 {
ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN
} else {
ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN
};
if partition_order == 0 {
bw.write_raw_u32(parameters[0], plen);
bw.write_rice_signed_block(residual, parameters[0]);
return;
}
let residual_samples = residual.len() as u32;
let blocksize = residual_samples + predictor_order;
let default_partition_samples = blocksize >> partition_order;
let mut k = 0usize;
let mut k_last = 0usize;
for (i, ¶m) in parameters
.iter()
.enumerate()
.take(1usize << partition_order)
{
let psamps = if i == 0 {
default_partition_samples - predictor_order
} else {
default_partition_samples
} as usize;
k += psamps;
bw.write_raw_u32(param, plen);
bw.write_rice_signed_block(&residual[k_last..k], param);
k_last = k;
}
}