use crate::mla::fmla;
use crate::{BIOLEPTIC_HEADER_SIZE, BiolepticError, BiolepticHeader, CompressionMethod};
use flate2::read::DeflateDecoder;
use osclet::{BorderMode, DaubechiesFamily, DwtSize, MultiLevelDwtRef, Osclet, SymletFamily};
use std::io::Read;
pub fn decompress(bytes: &[u8]) -> Result<Vec<f32>, BiolepticError> {
let header = BiolepticHeader::from_bytes(bytes)?;
let signal_length = header.signal_length as usize;
if signal_length > i32::MAX as usize {
return Err(BiolepticError::DecompressionError(format!(
"Can't decompress data bigger than {}, but data was {}",
i32::MAX,
signal_length,
)));
}
let dwt_levels = header.levels as usize;
if dwt_levels > 10 {
return Err(BiolepticError::DecompressionError(format!(
"Max supported level is 10 but it was {}",
dwt_levels,
)));
}
if dwt_levels == 0 {
return Err(BiolepticError::DecompressionError(format!(
"Min supported level is 1 but it was {}",
dwt_levels,
)));
}
let compression_method = header.compression_method()?;
let dwt_worker = match compression_method {
CompressionMethod::Cdf53 => Osclet::make_cdf53_f32(),
CompressionMethod::Cdf97 => Osclet::make_cdf97_f32(),
CompressionMethod::Db4 => {
Osclet::make_daubechies_f32(DaubechiesFamily::Db4, BorderMode::Wrap)
}
CompressionMethod::Sym4 => Osclet::make_symlet_f32(SymletFamily::Sym4, BorderMode::Wrap),
};
let mut levels_length: Vec<DwtSize> = vec![DwtSize::new(0); dwt_levels];
levels_length[0] = dwt_worker.dwt_size(signal_length);
for i in 1..dwt_levels {
let level_size = dwt_worker.dwt_size(levels_length[i - 1].approx_length);
levels_length[i] = level_size;
}
let compressed_size = header.compressed_size as usize;
let data_remainder_size = bytes.len() - BIOLEPTIC_HEADER_SIZE;
if data_remainder_size < compressed_size {
return Err(BiolepticError::DecompressionError(format!(
"Minimum data size is {}, but it was {}",
BIOLEPTIC_HEADER_SIZE + compressed_size,
bytes.len(),
)));
}
let compressed_data = &bytes[BIOLEPTIC_HEADER_SIZE..BIOLEPTIC_HEADER_SIZE + compressed_size];
let mut decoder = DeflateDecoder::new(compressed_data);
let mut decoded_data = vec![0u8; decoder.total_out() as usize];
decoder
.read_to_end(&mut decoded_data)
.map_err(|x| BiolepticError::DecompressionError(x.to_string()))?;
let quantized_data = decoded_data
.chunks_exact(2)
.map(|x| i16::from_le_bytes([x[0], x[1]]))
.collect::<Vec<i16>>();
let scale = header.scale;
if !(6..=12).contains(&scale) {
return Err(BiolepticError::DecompressionError(format!(
"Supported scales only [6, 12] but it was {scale}"
)));
}
let rcp_scale = 1. / (1 << scale) as f32;
let mut details = vec![];
let mut details_start = levels_length[dwt_levels - 1].approx_length;
for level in 0..dwt_levels {
let detail_level: Vec<f32> = quantized_data
[details_start..details_start + levels_length[level].details_length]
.iter()
.map(|&x| x as f32 * rcp_scale)
.collect();
details.push(detail_level);
details_start += levels_length[level].details_length;
}
let mut iwdt = dwt_worker
.multi_idwt(&MultiLevelDwtRef {
approximations: &quantized_data[..levels_length[dwt_levels - 1].approx_length]
.iter()
.map(|&x| x as f32 * rcp_scale)
.collect::<Vec<f32>>(),
details: details.iter().map(|x| x.as_slice()).collect(),
})
.map_err(|x| BiolepticError::UnderlyingDwtError(x.to_string()))?;
let range = header.max_f32() - header.min_f32();
let v_min = header.min_f32();
let v_mean = header.mean_f32();
for v in iwdt.iter_mut() {
*v = fmla(*v + v_mean, range, v_min);
}
if iwdt.len() != header.signal_length as usize {
iwdt.resize(header.signal_length as usize, 0.);
}
Ok(iwdt)
}