use std::num::NonZeroUsize;
#[cfg(feature = "serde")]
use serde::Deserialize;
#[cfg(feature = "serde")]
use serde::Serialize;
use super::constant;
use super::constant::qlpc::DEFAULT_ORDER as QLPC_DEFAULT_ORDER;
use super::constant::qlpc::DEFAULT_PRECISION as QLPC_DEFAULT_PRECISION;
use super::constant::qlpc::DEFAULT_TUKEY_ALPHA;
use super::constant::qlpc::MAX_ORDER as MAX_LPC_ORDER;
use super::constant::qlpc::MAX_PRECISION as QLPC_MAX_PRECISION;
use super::constant::rice::MAX_RICE_PARAMETER;
use super::constant::DEFAULT_ENTROPY_ESTIMATOR_PARTITIONS;
use super::constant::MAX_BLOCK_SIZE;
use super::constant::MAX_ENTROPY_ESTIMATOR_PARTITIONS;
use super::constant::MIN_BLOCK_SIZE;
use super::error::verify_range;
use super::error::verify_true;
use super::error::Verify;
use super::error::VerifyError;
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct Encoder {
pub block_size: usize,
pub multithread: bool,
pub workers: Option<NonZeroUsize>,
pub stereo_coding: StereoCoding,
pub subframe_coding: SubFrameCoding,
}
#[allow(clippy::derivable_impls)]
impl Default for Encoder {
fn default() -> Self {
Self {
stereo_coding: StereoCoding::default(),
subframe_coding: SubFrameCoding::default(),
block_size: constant::DEFAULT_BLOCK_SIZE,
multithread: cfg!(feature = "par"),
workers: None,
}
}
}
impl Verify for Encoder {
fn verify(&self) -> Result<(), VerifyError> {
verify_range!(
"block_size",
self.block_size,
MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE
)?;
self.stereo_coding
.verify()
.map_err(|err| err.within("stereo_coding"))?;
self.subframe_coding
.verify()
.map_err(|err| err.within("subframe_coding"))?;
Ok(())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct StereoCoding {
pub use_leftside: bool,
pub use_rightside: bool,
pub use_midside: bool,
}
impl Default for StereoCoding {
fn default() -> Self {
Self {
use_leftside: true,
use_rightside: true,
use_midside: true,
}
}
}
impl Verify for StereoCoding {
fn verify(&self) -> Result<(), VerifyError> {
Ok(())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct SubFrameCoding {
pub use_constant: bool,
pub use_fixed: bool,
pub use_lpc: bool,
pub fixed: Fixed,
pub qlpc: Qlpc,
pub prc: Prc,
}
impl Default for SubFrameCoding {
fn default() -> Self {
Self {
use_constant: true,
use_fixed: true,
use_lpc: true,
fixed: Fixed::default(),
qlpc: Qlpc::default(),
prc: Prc::default(),
}
}
}
impl Verify for SubFrameCoding {
fn verify(&self) -> Result<(), VerifyError> {
self.qlpc.verify().map_err(|err| err.within("qlpc"))?;
self.prc.verify().map_err(|err| err.within("prc"))?;
Ok(())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct Prc {
pub max_parameter: usize,
}
impl Default for Prc {
fn default() -> Self {
Self {
max_parameter: MAX_RICE_PARAMETER,
}
}
}
impl Verify for Prc {
fn verify(&self) -> Result<(), VerifyError> {
verify_range!("max_parameter", self.max_parameter, ..=MAX_RICE_PARAMETER)?;
Ok(())
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct Fixed {
pub max_order: usize,
pub order_sel: OrderSel,
}
impl Verify for Fixed {
fn verify(&self) -> Result<(), VerifyError> {
verify_range!(
"max_order",
self.max_order,
..=(constant::fixed::MAX_LPC_ORDER)
)?;
Ok(())
}
}
impl Default for Fixed {
fn default() -> Self {
Self {
max_order: constant::fixed::MAX_LPC_ORDER,
order_sel: OrderSel::default(),
}
}
}
#[derive(Clone, Debug)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(default))]
#[non_exhaustive]
pub struct Qlpc {
pub lpc_order: usize,
pub quant_precision: usize,
pub use_direct_mse: bool,
pub mae_optimization_steps: usize,
pub window: Window,
}
impl Default for Qlpc {
fn default() -> Self {
Self {
lpc_order: QLPC_DEFAULT_ORDER,
quant_precision: QLPC_DEFAULT_PRECISION,
use_direct_mse: false,
mae_optimization_steps: 0,
window: Window::default(),
}
}
}
impl Verify for Qlpc {
fn verify(&self) -> Result<(), VerifyError> {
verify_range!("lpc_order", self.lpc_order, 1..=MAX_LPC_ORDER)?;
verify_range!(
"quant_precision",
self.quant_precision,
1..=QLPC_MAX_PRECISION
)?;
if cfg!(not(feature = "experimental")) {
verify_true!(
"use_direct_mse",
!self.use_direct_mse,
"this feature is only available in `experimental` build."
)?;
verify_true!(
"mae_optimization_steps",
self.mae_optimization_steps == 0,
"this feature is only available in `experimental` build."
)?;
}
self.window.verify().map_err(|err| err.within("window"))?;
Ok(())
}
}
#[derive(Clone, Debug, PartialEq, PartialOrd)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type"))]
#[non_exhaustive]
pub enum Window {
Rectangle,
Tukey {
alpha: f32,
},
}
impl Eq for Window {}
impl Default for Window {
fn default() -> Self {
Self::Tukey {
alpha: DEFAULT_TUKEY_ALPHA,
}
}
}
impl Verify for Window {
fn verify(&self) -> Result<(), VerifyError> {
match *self {
Self::Rectangle => Ok(()),
Self::Tukey { alpha } => {
if (0.0..=1.0).contains(&alpha) {
Ok(())
} else {
Err(VerifyError::new(
"tukey.alpha",
"alpha must be in range between 0 and 1",
))
}
}
}
}
}
#[cfg(feature = "serde")]
const fn default_partition_count() -> usize {
DEFAULT_ENTROPY_ESTIMATOR_PARTITIONS
}
#[derive(Clone, Debug)]
#[non_exhaustive]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "type"))]
pub enum OrderSel {
BitCount,
ApproxEnt {
#[cfg_attr(feature = "serde", serde(default = "default_partition_count"))]
partitions: usize,
},
}
impl Default for OrderSel {
fn default() -> Self {
Self::ApproxEnt {
partitions: DEFAULT_ENTROPY_ESTIMATOR_PARTITIONS,
}
}
}
impl Verify for OrderSel {
fn verify(&self) -> Result<(), VerifyError> {
match *self {
Self::BitCount => Ok(()),
Self::ApproxEnt { partitions } => {
verify_range!(
"ApproxEnt.partitions",
partitions,
1..=MAX_ENTROPY_ESTIMATOR_PARTITIONS
)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verification_for_encoder() {
{
let config = Encoder::default();
config.verify().unwrap();
}
{
let config = Encoder {
block_size: 1234,
..Default::default()
};
config.verify().unwrap();
}
{
let config = Encoder {
block_size: 1,
..Default::default()
};
config.verify().unwrap_err();
}
{
let config = Encoder {
block_size: 123_456,
..Default::default()
};
config.verify().unwrap_err();
}
}
#[test]
fn verification_for_stereo_coding() {
let config = StereoCoding::default();
config.verify().unwrap();
}
#[test]
fn verification_for_subframe_coding() {
{
let config = SubFrameCoding::default();
config.verify().unwrap();
}
{
let mut config = SubFrameCoding::default();
config.prc.max_parameter = 1234;
config.verify().unwrap_err();
}
}
#[test]
fn verification_for_prc() {
{
let config = Prc::default();
config.verify().unwrap();
}
{
let config = Prc {
max_parameter: 18,
..Default::default()
};
config.verify().unwrap_err();
}
}
#[test]
fn verification_for_qlpc() {
{
let config = Qlpc::default();
config.verify().unwrap();
}
{
let config = Qlpc {
lpc_order: 39,
..Default::default()
};
config.verify().unwrap_err();
}
{
let config = Qlpc {
quant_precision: 256,
..Default::default()
};
config.verify().unwrap_err();
}
{
let config = Qlpc {
use_direct_mse: true,
..Default::default()
};
if cfg!(feature = "experimental") {
config.verify().unwrap();
} else {
config.verify().unwrap_err();
}
}
{
let config = Qlpc {
mae_optimization_steps: 20,
..Default::default()
};
if cfg!(feature = "experimental") {
config.verify().unwrap();
} else {
config.verify().unwrap_err();
}
}
}
#[cfg(feature = "serde")]
#[test]
fn serialization() -> Result<(), toml::ser::Error> {
let config = Encoder::default();
toml::to_string(&config)?;
Ok(())
}
#[cfg(feature = "serde")]
#[test]
fn deserialization() {
let src = "
[subframe_coding.qlpc]
lpc_order = 7
";
let config: Encoder = toml::from_str(src).expect("Parse error.");
assert_eq!(config.subframe_coding.qlpc.lpc_order, 7);
assert_eq!(
config.subframe_coding.qlpc.quant_precision,
QLPC_DEFAULT_PRECISION
);
assert_eq!(
config.subframe_coding.qlpc.quant_precision,
QLPC_DEFAULT_PRECISION
);
assert_eq!(config.block_size, constant::DEFAULT_BLOCK_SIZE);
assert!(config.subframe_coding.use_lpc);
}
#[cfg(feature = "serde")]
#[test]
fn if_empty_source_yields_default_config() {
let empty_src = "";
let config: Encoder = toml::from_str(empty_src).expect("Parse error.");
let default_config: Encoder = Encoder::default();
eprintln!(
"## Current default config\n\n{}",
toml::to_string(&config).unwrap()
);
assert_eq!(toml::to_string(&config), toml::to_string(&default_config));
}
#[cfg(feature = "serde")]
#[test]
fn deserialize_and_verify() {
let src = "
[subframe_coding.qlpc]
lpc_order = 256
";
let config: Encoder = toml::from_str(src).expect("Parse error.");
let verify_result = config.verify();
assert!(verify_result.is_err());
eprintln!("{}", verify_result.err().unwrap());
}
}