use serde::Deserialize;
use serde::Serialize;
use super::constant::MAX_BLOCKSIZE_SUPPORTED;
use super::constant::MAX_LPC_ORDER;
use super::constant::MAX_RICE_PARAMETER;
use super::constant::MIN_BLOCKSIZE_SUPPORTED;
use super::constant::QLPC_DEFAULT_ORDER;
use super::constant::QLPC_DEFAULT_PRECISION;
use super::constant::QLPC_MAX_PRECISION;
use super::error::Verify;
use super::error::VerifyError;
use super::lpc::Window;
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct Encoder {
pub block_sizes: Vec<usize>,
pub block_size_search_beam_width: Option<usize>,
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_sizes: vec![4096usize],
block_size_search_beam_width: None,
}
}
}
impl Verify for Encoder {
fn verify(&self) -> Result<(), VerifyError> {
if self.block_sizes.is_empty() {
return Err(VerifyError::new(
"block_sizes",
"Must specify at least one block size.",
));
}
if self.block_size_search_beam_width == Some(0) {
return Err(VerifyError::new(
"block_size_search_beam_width",
"Must be more than 1.",
));
}
for (i, &bs) in self.block_sizes.iter().enumerate() {
if bs > MAX_BLOCKSIZE_SUPPORTED {
return Err(VerifyError::new(
&format!("block_sizes[{}]", i),
&format!("Must be less than {}", MAX_BLOCKSIZE_SUPPORTED),
));
} else if bs < MIN_BLOCKSIZE_SUPPORTED {
return Err(VerifyError::new(
&format!("block_sizes[{}]", i),
&format!("Must be more than {}", MIN_BLOCKSIZE_SUPPORTED),
));
}
}
self.stereo_coding
.verify()
.map_err(|err| err.within("stereo_coding"))?;
self.subframe_coding
.verify()
.map_err(|err| err.within("subframe_coding"))?;
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
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(Serialize, Deserialize, Debug)]
#[serde(default)]
pub struct SubFrameCoding {
pub use_constant: bool,
pub use_fixed: bool,
pub use_lpc: bool,
pub qlpc: Qlpc,
pub prc: Prc,
}
impl Default for SubFrameCoding {
fn default() -> Self {
Self {
use_constant: true,
use_fixed: true,
use_lpc: true,
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(Serialize, Deserialize, Debug)]
#[serde(default)]
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> {
if self.max_parameter > MAX_RICE_PARAMETER {
return Err(VerifyError::new(
"max_parameter",
&format!("Must not exceed {}", MAX_RICE_PARAMETER),
));
}
Ok(())
}
}
#[derive(Serialize, Deserialize, Debug)]
#[serde(default)]
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> {
if self.lpc_order > MAX_LPC_ORDER {
return Err(VerifyError::new(
"lpc_order",
&format!("Must not exceed {}", MAX_LPC_ORDER),
));
}
if self.quant_precision > QLPC_MAX_PRECISION {
return Err(VerifyError::new(
"quant_precision",
&format!("Must not exceed {}", QLPC_MAX_PRECISION),
));
}
if self.quant_precision == 0 {
return Err(VerifyError::new("quant_precision", "Must not be zero"));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::super::error::Verify;
use super::*;
#[test]
fn serialization() {
let config = Encoder::default();
assert!(toml::to_string(&config).is_ok());
}
#[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_sizes, &[4096]);
assert!(config.subframe_coding.use_lpc);
}
#[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));
}
#[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());
}
}