use crate::hca::ath::ath_init;
use crate::hca::bitreader::BitReader;
use crate::hca::cipher::{cipher_decrypt, cipher_init};
use crate::hca::imdct::imdct_transform;
use crate::hca::tables::{
DEQUANTIZER_RANGE_TABLE, DEQUANTIZER_SCALING_TABLE, INTENSITY_RATIO_TABLE, INVERT_TABLE,
MAX_BIT_TABLE, READ_BIT_TABLE, READ_VAL_TABLE, SCALE_CONVERSION_TABLE,
};
use thiserror::Error;
pub const HCA_VERSION_101: u32 = 0x0101;
pub const HCA_VERSION_102: u32 = 0x0102;
pub const HCA_VERSION_103: u32 = 0x0103;
pub const HCA_VERSION_200: u32 = 0x0200;
pub const HCA_VERSION_300: u32 = 0x0300;
pub const HCA_MIN_FRAME_SIZE: u32 = 0x8;
pub const HCA_MAX_FRAME_SIZE: u32 = 0xFFFF;
pub const HCA_MASK: u32 = 0x7F7F7F7F;
pub const HCA_SUBFRAMES: usize = 8;
pub const HCA_SAMPLES_PER_SUBFRAME: usize = 128;
pub const HCA_SAMPLES_PER_FRAME: usize = HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME;
pub const HCA_MDCT_BITS: usize = 7;
pub const HCA_MIN_CHANNELS: u32 = 1;
pub const HCA_MAX_CHANNELS: usize = 16;
pub const HCA_MIN_SAMPLE_RATE: u32 = 1;
pub const HCA_MAX_SAMPLE_RATE: u32 = 0x7FFFFF;
pub const HCA_DEFAULT_RANDOM: u32 = 1;
#[derive(Debug, Error)]
pub enum HcaError {
#[error("invalid parameters")]
InvalidParams,
#[error("invalid HCA header")]
InvalidHeader,
#[error("checksum failed")]
ChecksumFailed,
#[error("sync word not found")]
SyncError,
#[error("unpack error: {0}")]
UnpackError(String),
#[error("bitreader error")]
BitreaderError,
#[error("unsupported version: {0}")]
UnsupportedVersion(u32),
#[error("decoder not initialized")]
NotInitialized,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ChannelType {
#[default]
Discrete,
StereoPrimary,
StereoSecondary,
}
#[derive(Clone)]
pub struct StChannel {
pub channel_type: ChannelType,
pub coded_count: usize,
pub intensity: [u8; HCA_SUBFRAMES],
pub scale_factors: [u8; HCA_SAMPLES_PER_SUBFRAME],
pub resolution: [u8; HCA_SAMPLES_PER_SUBFRAME],
pub noises: [u8; HCA_SAMPLES_PER_SUBFRAME],
pub noise_count: usize,
pub valid_count: usize,
pub gain: [f32; HCA_SAMPLES_PER_SUBFRAME],
pub spectra: [[f32; HCA_SAMPLES_PER_SUBFRAME]; HCA_SUBFRAMES],
pub temp: [f32; HCA_SAMPLES_PER_SUBFRAME],
pub dct: [f32; HCA_SAMPLES_PER_SUBFRAME],
pub imdct_previous: [f32; HCA_SAMPLES_PER_SUBFRAME],
pub wave: [[f32; HCA_SAMPLES_PER_SUBFRAME]; HCA_SUBFRAMES],
}
impl Default for StChannel {
fn default() -> Self {
Self {
channel_type: ChannelType::Discrete,
coded_count: 0,
intensity: [0; HCA_SUBFRAMES],
scale_factors: [0; HCA_SAMPLES_PER_SUBFRAME],
resolution: [0; HCA_SAMPLES_PER_SUBFRAME],
noises: [0; HCA_SAMPLES_PER_SUBFRAME],
noise_count: 0,
valid_count: 0,
gain: [0.0; HCA_SAMPLES_PER_SUBFRAME],
spectra: [[0.0; HCA_SAMPLES_PER_SUBFRAME]; HCA_SUBFRAMES],
temp: [0.0; HCA_SAMPLES_PER_SUBFRAME],
dct: [0.0; HCA_SAMPLES_PER_SUBFRAME],
imdct_previous: [0.0; HCA_SAMPLES_PER_SUBFRAME],
wave: [[0.0; HCA_SAMPLES_PER_SUBFRAME]; HCA_SUBFRAMES],
}
}
}
#[derive(Debug, Clone)]
pub struct HcaInfo {
pub version: u32,
pub header_size: u32,
pub sampling_rate: u32,
pub channel_count: u32,
pub block_size: u32,
pub block_count: u32,
pub encoder_delay: u32,
pub encoder_padding: u32,
pub loop_enabled: bool,
pub loop_start_block: u32,
pub loop_end_block: u32,
pub loop_start_delay: u32,
pub loop_end_padding: u32,
pub samples_per_block: usize,
pub comment: String,
pub encryption_enabled: bool,
}
const CRC16_TABLE: [u16; 256] = [
0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, 0x8033, 0x0036, 0x003C, 0x8039,
0x0028, 0x802D, 0x8027, 0x0022, 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072,
0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, 0x80C3, 0x00C6, 0x00CC, 0x80C9,
0x00D8, 0x80DD, 0x80D7, 0x00D2, 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1,
0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, 0x8093, 0x0096, 0x009C, 0x8099,
0x0088, 0x808D, 0x8087, 0x0082, 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192,
0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, 0x01E0, 0x81E5, 0x81EF, 0x01EA,
0x81FB, 0x01FE, 0x01F4, 0x81F1, 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2,
0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, 0x8173, 0x0176, 0x017C, 0x8179,
0x0168, 0x816D, 0x8167, 0x0162, 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132,
0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, 0x8303, 0x0306, 0x030C, 0x8309,
0x0318, 0x831D, 0x8317, 0x0312, 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321,
0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, 0x8353, 0x0356, 0x035C, 0x8359,
0x0348, 0x834D, 0x8347, 0x0342, 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1,
0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, 0x83A3, 0x03A6, 0x03AC, 0x83A9,
0x03B8, 0x83BD, 0x83B7, 0x03B2, 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381,
0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, 0x82B3, 0x02B6, 0x02BC, 0x82B9,
0x02A8, 0x82AD, 0x82A7, 0x02A2, 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2,
0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, 0x8243, 0x0246, 0x024C, 0x8249,
0x0258, 0x825D, 0x8257, 0x0252, 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261,
0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, 0x8213, 0x0216, 0x021C, 0x8219,
0x0208, 0x820D, 0x8207, 0x0202,
];
fn crc16_checksum(data: &[u8]) -> u16 {
let mut sum: u16 = 0;
for &byte in data {
sum = (sum << 8) ^ CRC16_TABLE[((sum >> 8) ^ byte as u16) as usize];
}
sum
}
fn header_ceil2(a: u32, b: u32) -> u32 {
if b < 1 {
return 0;
}
let mut result = a / b;
if !a.is_multiple_of(b) {
result += 1;
}
result
}
pub struct ClHca {
is_valid: bool,
pub version: u32,
pub header_size: u32,
pub channels: u32,
pub sample_rate: u32,
pub frame_count: u32,
pub encoder_delay: u32,
pub encoder_padding: u32,
pub frame_size: u32,
pub min_resolution: u32,
pub max_resolution: u32,
pub track_count: u32,
pub channel_config: u32,
pub stereo_type: u32,
pub total_band_count: u32,
pub base_band_count: u32,
pub stereo_band_count: u32,
pub bands_per_hfr_group: u32,
pub ms_stereo: u32,
pub reserved: u32,
pub vbr_max_frame_size: u32,
pub vbr_noise_level: u32,
pub ath_type: u32,
pub loop_start_frame: u32,
pub loop_end_frame: u32,
pub loop_start_delay: u32,
pub loop_end_padding: u32,
pub loop_flag: bool,
pub ciph_type: u32,
pub keycode: u64,
pub rva_volume: f32,
pub comment_len: usize,
pub comment: [u8; 256],
pub hfr_group_count: u32,
pub ath_curve: [u8; HCA_SAMPLES_PER_SUBFRAME],
pub cipher_table: [u8; 256],
pub random: u32,
pub channel: [StChannel; HCA_MAX_CHANNELS],
}
impl Default for ClHca {
fn default() -> Self {
Self::new()
}
}
impl ClHca {
pub fn new() -> Self {
Self {
is_valid: false,
version: 0,
header_size: 0,
channels: 0,
sample_rate: 0,
frame_count: 0,
encoder_delay: 0,
encoder_padding: 0,
frame_size: 0,
min_resolution: 0,
max_resolution: 0,
track_count: 0,
channel_config: 0,
stereo_type: 0,
total_band_count: 0,
base_band_count: 0,
stereo_band_count: 0,
bands_per_hfr_group: 0,
ms_stereo: 0,
reserved: 0,
vbr_max_frame_size: 0,
vbr_noise_level: 0,
ath_type: 0,
loop_start_frame: 0,
loop_end_frame: 0,
loop_start_delay: 0,
loop_end_padding: 0,
loop_flag: false,
ciph_type: 0,
keycode: 0,
rva_volume: 1.0,
comment_len: 0,
comment: [0; 256],
hfr_group_count: 0,
ath_curve: [0; HCA_SAMPLES_PER_SUBFRAME],
cipher_table: [0; 256],
random: HCA_DEFAULT_RANDOM,
channel: std::array::from_fn(|_| StChannel::default()),
}
}
pub fn clear(&mut self) {
*self = Self::new();
}
pub fn set_key(&mut self, keycode: u64) {
self.keycode = keycode;
if self.is_valid {
cipher_init(&mut self.cipher_table, self.ciph_type, self.keycode);
}
}
pub fn is_hca_file(data: &[u8]) -> Option<usize> {
if data.len() < 8 {
return None;
}
let mut br = BitReader::new(data);
let sig = br.peek(32) & HCA_MASK;
if sig == 0x48434100 {
br.skip(32 + 16);
let header_size = br.read(16) as usize;
if header_size == 0 {
return None;
}
Some(header_size)
} else {
None
}
}
pub fn get_info(&self) -> Result<HcaInfo, HcaError> {
if !self.is_valid {
return Err(HcaError::NotInitialized);
}
Ok(HcaInfo {
version: self.version,
header_size: self.header_size,
sampling_rate: self.sample_rate,
channel_count: self.channels,
block_size: self.frame_size,
block_count: self.frame_count,
encoder_delay: self.encoder_delay,
encoder_padding: self.encoder_padding,
loop_enabled: self.loop_flag,
loop_start_block: self.loop_start_frame,
loop_end_block: self.loop_end_frame,
loop_start_delay: self.loop_start_delay,
loop_end_padding: self.loop_end_padding,
samples_per_block: HCA_SAMPLES_PER_FRAME,
comment: if self.comment_len > 0 {
String::from_utf8_lossy(&self.comment[..self.comment_len]).to_string()
} else {
String::new()
},
encryption_enabled: self.ciph_type == 56,
})
}
pub fn decode_header(&mut self, data: &[u8]) -> Result<(), HcaError> {
if data.len() < 8 {
return Err(HcaError::InvalidParams);
}
self.is_valid = false;
let mut br = BitReader::new(data);
self.decode_base_header(&mut br, data)?;
self.decode_chunks(&mut br)?;
self.validate_and_initialize()?;
self.is_valid = true;
Ok(())
}
fn decode_base_header(&mut self, br: &mut BitReader, data: &[u8]) -> Result<(), HcaError> {
if (br.peek(32) & HCA_MASK) != 0x48434100 {
return Err(HcaError::InvalidHeader);
}
br.skip(32);
self.version = br.read(16);
self.header_size = br.read(16);
if self.version != HCA_VERSION_101
&& self.version != HCA_VERSION_102
&& self.version != HCA_VERSION_103
&& self.version != HCA_VERSION_200
&& self.version != HCA_VERSION_300
{
return Err(HcaError::UnsupportedVersion(self.version));
}
if data.len() < self.header_size as usize {
return Err(HcaError::InvalidHeader);
}
if crc16_checksum(&data[..self.header_size as usize]) != 0 {
return Err(HcaError::ChecksumFailed);
}
Ok(())
}
fn decode_chunks(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
self.decode_fmt_chunk(br)?;
self.decode_comp_dec_chunk(br)?;
self.decode_vbr_chunk(br);
self.decode_ath_chunk(br);
self.decode_loop_chunk(br)?;
self.decode_cipher_chunk(br)?;
self.decode_rva_chunk(br);
self.decode_comment_chunk(br);
Ok(())
}
fn decode_fmt_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
if (br.peek(32) & HCA_MASK) != 0x666D7400 {
return Err(HcaError::InvalidHeader);
}
br.skip(32);
self.channels = br.read(8);
self.sample_rate = br.read(24);
self.frame_count = br.read(32);
self.encoder_delay = br.read(16);
self.encoder_padding = br.read(16);
if self.channels < HCA_MIN_CHANNELS || self.channels > HCA_MAX_CHANNELS as u32 {
return Err(HcaError::InvalidHeader);
}
if self.frame_count == 0 {
return Err(HcaError::InvalidHeader);
}
if self.sample_rate < HCA_MIN_SAMPLE_RATE || self.sample_rate > HCA_MAX_SAMPLE_RATE {
return Err(HcaError::InvalidHeader);
}
Ok(())
}
fn decode_comp_dec_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
let chunk_type = br.peek(32) & HCA_MASK;
if chunk_type == 0x636F6D70 {
self.decode_comp_chunk(br)
} else if chunk_type == 0x64656300 {
self.decode_dec_chunk(br)
} else {
Err(HcaError::InvalidHeader)
}
}
fn decode_comp_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
br.skip(32);
self.frame_size = br.read(16);
self.min_resolution = br.read(8);
self.max_resolution = br.read(8);
self.track_count = br.read(8);
self.channel_config = br.read(8);
self.total_band_count = br.read(8);
self.base_band_count = br.read(8);
self.stereo_band_count = br.read(8);
self.bands_per_hfr_group = br.read(8);
self.ms_stereo = br.read(8);
self.reserved = br.read(8);
Ok(())
}
fn decode_dec_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
br.skip(32);
self.frame_size = br.read(16);
self.min_resolution = br.read(8);
self.max_resolution = br.read(8);
self.total_band_count = br.read(8) + 1;
self.base_band_count = br.read(8) + 1;
self.track_count = br.read(4);
self.channel_config = br.read(4);
self.stereo_type = br.read(8);
if self.stereo_type == 0 {
self.base_band_count = self.total_band_count;
}
self.stereo_band_count = self.total_band_count - self.base_band_count;
self.bands_per_hfr_group = 0;
Ok(())
}
fn decode_vbr_chunk(&mut self, br: &mut BitReader) {
if (br.peek(32) & HCA_MASK) == 0x76627200 {
br.skip(32);
self.vbr_max_frame_size = br.read(16);
self.vbr_noise_level = br.read(16);
} else {
self.vbr_max_frame_size = 0;
self.vbr_noise_level = 0;
}
}
fn decode_ath_chunk(&mut self, br: &mut BitReader) {
if (br.peek(32) & HCA_MASK) == 0x61746800 {
br.skip(32);
self.ath_type = br.read(16);
} else {
self.ath_type = if self.version < HCA_VERSION_200 { 1 } else { 0 };
}
}
fn decode_loop_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
if (br.peek(32) & HCA_MASK) == 0x6C6F6F70 {
br.skip(32);
self.loop_start_frame = br.read(32);
self.loop_end_frame = br.read(32);
self.loop_start_delay = br.read(16);
self.loop_end_padding = br.read(16);
self.loop_flag = true;
if !(self.loop_start_frame <= self.loop_end_frame
&& self.loop_end_frame < self.frame_count)
{
return Err(HcaError::InvalidHeader);
}
} else {
self.loop_flag = false;
}
Ok(())
}
fn decode_cipher_chunk(&mut self, br: &mut BitReader) -> Result<(), HcaError> {
if (br.peek(32) & HCA_MASK) == 0x63697068 {
br.skip(32);
self.ciph_type = br.read(16);
if !(self.ciph_type == 0 || self.ciph_type == 1 || self.ciph_type == 56) {
return Err(HcaError::InvalidHeader);
}
} else {
self.ciph_type = 0;
}
Ok(())
}
fn decode_rva_chunk(&mut self, br: &mut BitReader) {
if (br.peek(32) & HCA_MASK) == 0x72766100 {
br.skip(32);
let rva_int = br.read(32);
self.rva_volume = f32::from_bits(rva_int);
} else {
self.rva_volume = 1.0;
}
}
fn decode_comment_chunk(&mut self, br: &mut BitReader) {
if (br.peek(32) & HCA_MASK) == 0x636F6D6D {
br.skip(32);
self.comment_len = br.read(8) as usize;
for i in 0..self.comment_len.min(255) {
self.comment[i] = br.read(8) as u8;
}
if self.comment_len < 256 {
self.comment[self.comment_len] = 0;
}
} else {
self.comment_len = 0;
}
}
fn validate_and_initialize(&mut self) -> Result<(), HcaError> {
self.validate_frame_and_resolution()?;
self.validate_tracks_and_bands()?;
self.initialize_decoder_state()?;
Ok(())
}
fn validate_frame_and_resolution(&self) -> Result<(), HcaError> {
if self.frame_size < HCA_MIN_FRAME_SIZE || self.frame_size > HCA_MAX_FRAME_SIZE {
return Err(HcaError::InvalidHeader);
}
if self.version <= HCA_VERSION_200 {
if self.min_resolution != 1 || self.max_resolution != 15 {
return Err(HcaError::InvalidHeader);
}
} else if self.min_resolution > self.max_resolution || self.max_resolution > 15 {
return Err(HcaError::InvalidHeader);
}
Ok(())
}
fn validate_tracks_and_bands(&mut self) -> Result<(), HcaError> {
if self.track_count == 0 {
self.track_count = 1;
}
if self.track_count > self.channels {
return Err(HcaError::InvalidHeader);
}
let max = HCA_SAMPLES_PER_SUBFRAME as u32;
if self.total_band_count > max
|| self.base_band_count > max
|| self.stereo_band_count > max
|| self.base_band_count + self.stereo_band_count > max
|| self.bands_per_hfr_group > max
{
return Err(HcaError::InvalidHeader);
}
self.hfr_group_count = header_ceil2(
self.total_band_count - self.base_band_count - self.stereo_band_count,
self.bands_per_hfr_group,
);
Ok(())
}
fn initialize_decoder_state(&mut self) -> Result<(), HcaError> {
if !ath_init(&mut self.ath_curve, self.ath_type, self.sample_rate) {
return Err(HcaError::InvalidHeader);
}
cipher_init(&mut self.cipher_table, self.ciph_type, self.keycode);
self.init_channels()?;
self.random = HCA_DEFAULT_RANDOM;
Ok(())
}
fn init_channels(&mut self) -> Result<(), HcaError> {
let mut channel_types = [ChannelType::Discrete; HCA_MAX_CHANNELS];
let channels_per_track = self.channels / self.track_count;
if self.stereo_band_count > 0 && channels_per_track > 1 {
for i in 0..self.track_count as usize {
let ct = &mut channel_types[i * channels_per_track as usize..];
match channels_per_track {
2 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
}
3 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
ct[2] = ChannelType::Discrete;
}
4 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
if self.channel_config == 0 {
ct[2] = ChannelType::StereoPrimary;
ct[3] = ChannelType::StereoSecondary;
} else {
ct[2] = ChannelType::Discrete;
ct[3] = ChannelType::Discrete;
}
}
5 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
ct[2] = ChannelType::Discrete;
if self.channel_config <= 2 {
ct[3] = ChannelType::StereoPrimary;
ct[4] = ChannelType::StereoSecondary;
} else {
ct[3] = ChannelType::Discrete;
ct[4] = ChannelType::Discrete;
}
}
6 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
ct[2] = ChannelType::Discrete;
ct[3] = ChannelType::Discrete;
ct[4] = ChannelType::StereoPrimary;
ct[5] = ChannelType::StereoSecondary;
}
7 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
ct[2] = ChannelType::Discrete;
ct[3] = ChannelType::Discrete;
ct[4] = ChannelType::StereoPrimary;
ct[5] = ChannelType::StereoSecondary;
ct[6] = ChannelType::Discrete;
}
8 => {
ct[0] = ChannelType::StereoPrimary;
ct[1] = ChannelType::StereoSecondary;
ct[2] = ChannelType::Discrete;
ct[3] = ChannelType::Discrete;
ct[4] = ChannelType::StereoPrimary;
ct[5] = ChannelType::StereoSecondary;
ct[6] = ChannelType::StereoPrimary;
ct[7] = ChannelType::StereoSecondary;
}
_ => {}
}
}
}
for (i, &ct) in channel_types
.iter()
.enumerate()
.take(self.channels as usize)
{
self.channel[i].channel_type = ct;
if ct != ChannelType::StereoSecondary {
self.channel[i].coded_count =
(self.base_band_count + self.stereo_band_count) as usize;
} else {
self.channel[i].coded_count = self.base_band_count as usize;
}
}
Ok(())
}
pub fn decode_reset(&mut self) {
if !self.is_valid {
return;
}
self.random = HCA_DEFAULT_RANDOM;
for i in 0..self.channels as usize {
self.channel[i].imdct_previous.fill(0.0);
}
}
pub fn read_samples_16(&self, samples: &mut [i16]) {
const SCALE_F: f32 = 32768.0;
let mut idx = 0;
for i in 0..HCA_SUBFRAMES {
for j in 0..HCA_SAMPLES_PER_SUBFRAME {
for k in 0..self.channels as usize {
let f = self.channel[k].wave[i][j];
let s = (f * SCALE_F) as i32;
samples[idx] = s.clamp(-32768, 32767) as i16;
idx += 1;
}
}
}
}
pub fn read_samples(&self, samples: &mut [f32]) {
let mut idx = 0;
for i in 0..HCA_SUBFRAMES {
for j in 0..HCA_SAMPLES_PER_SUBFRAME {
for k in 0..self.channels as usize {
samples[idx] = self.channel[k].wave[i][j];
idx += 1;
}
}
}
}
pub fn test_block(&mut self, data: &mut [u8]) -> i32 {
if self.is_empty_block(data) {
return 0;
}
let bit_pos = match self.decode_block_unpack(data) {
Ok(pos) => pos,
Err(_) => return -1,
};
let err = self.validate_bitreader(data, bit_pos);
if err != 0 {
return err;
}
self.decode_block_transform();
self.evaluate_decode_quality()
}
fn is_empty_block(&self, data: &[u8]) -> bool {
for &byte in &data[0x02..(data.len().saturating_sub(0x02))] {
if byte != 0 {
return false;
}
}
true
}
fn validate_bitreader(&self, data: &[u8], bit_pos: usize) -> i32 {
let bits_max = self.frame_size as usize * 8;
if bit_pos + 14 > bits_max {
return -2; }
let byte_start = if !bit_pos.is_multiple_of(8) {
bit_pos / 8 + 1
} else {
bit_pos / 8
};
for &byte in &data[byte_start..(self.frame_size as usize).saturating_sub(0x02)] {
if byte != 0 {
return -1;
}
}
0
}
fn evaluate_decode_quality(&self) -> i32 {
const FRAME_SAMPLES: usize = HCA_SUBFRAMES * HCA_SAMPLES_PER_SUBFRAME;
const SCALE: f32 = 32768.0;
let mut clips = 0;
let mut blanks = 0;
let mut channel_blanks = [0i32; HCA_MAX_CHANNELS];
for (ch, channel_blank) in channel_blanks
.iter_mut()
.enumerate()
.take(self.channels as usize)
{
for sf in 0..HCA_SUBFRAMES {
for s in 0..HCA_SAMPLES_PER_SUBFRAME {
let fsample = self.channel[ch].wave[sf][s];
if !(-1.0..=1.0).contains(&fsample) {
clips += 1;
} else {
let psample = (fsample * SCALE) as i32;
if psample == 0 || psample == -1 {
blanks += 1;
*channel_blank += 1;
}
}
}
}
}
self.calculate_score(clips, blanks, &channel_blanks, FRAME_SAMPLES)
}
fn calculate_score(
&self,
mut clips: i32,
blanks: i32,
channel_blanks: &[i32],
frame_samples: usize,
) -> i32 {
if clips == 1 {
clips += 1;
}
if clips > 1 {
return clips;
}
if blanks == self.channels as i32 * frame_samples as i32 {
return 0;
}
if self.channels >= 2
&& channel_blanks[0] == frame_samples as i32
&& channel_blanks[1] != frame_samples as i32
{
return 3;
}
1
}
pub fn decode_block(&mut self, data: &mut [u8]) -> Result<(), HcaError> {
let _bit_pos = self.decode_block_unpack(data)?;
self.decode_block_transform();
Ok(())
}
fn decode_block_unpack(&mut self, data: &mut [u8]) -> Result<usize, HcaError> {
if !self.is_valid {
return Err(HcaError::InvalidParams);
}
if data.len() < self.frame_size as usize {
return Err(HcaError::InvalidParams);
}
let mut br = BitReader::new(data);
let sync = br.read(16);
if sync != 0xFFFF {
return Err(HcaError::SyncError);
}
if crc16_checksum(&data[..self.frame_size as usize]) != 0 {
return Err(HcaError::ChecksumFailed);
}
cipher_decrypt(&self.cipher_table, &mut data[..self.frame_size as usize]);
let mut br = BitReader::with_offset(data, 2);
let frame_acceptable_noise_level = br.read(9);
let frame_evaluation_boundary = br.read(7);
let packed_noise_level =
(frame_acceptable_noise_level << 8).wrapping_sub(frame_evaluation_boundary);
for ch in 0..self.channels as usize {
self.unpack_scale_factors(ch, &mut br)?;
self.unpack_intensity(ch, &mut br)?;
self.calculate_resolution(ch, packed_noise_level);
self.calculate_gain(ch);
}
for subframe in 0..HCA_SUBFRAMES {
for ch in 0..self.channels as usize {
self.dequantize_coefficients(ch, &mut br, subframe);
}
}
Ok(br.position())
}
fn unpack_scale_factors(&mut self, ch: usize, br: &mut BitReader) -> Result<(), HcaError> {
let channel = &mut self.channel[ch];
let mut cs_count = channel.coded_count;
let extra_count: usize;
let delta_bits = br.read(3) as u8;
if channel.channel_type == ChannelType::StereoSecondary
|| self.hfr_group_count == 0
|| self.version <= HCA_VERSION_200
{
extra_count = 0;
} else {
extra_count = self.hfr_group_count as usize;
cs_count += extra_count;
if cs_count > HCA_SAMPLES_PER_SUBFRAME {
return Err(HcaError::UnpackError("invalid coded count".into()));
}
}
if delta_bits >= 6 {
for i in 0..cs_count {
channel.scale_factors[i] = br.read(6) as u8;
}
} else if delta_bits > 0 {
let expected_delta = ((1 << delta_bits) - 1) as u8;
let mut value = br.read(6) as u8;
channel.scale_factors[0] = value;
for i in 1..cs_count {
let delta = br.read(delta_bits as usize) as u8;
if delta == expected_delta {
value = br.read(6) as u8;
} else {
let scalefactor_test =
value as i32 + (delta as i32 - (expected_delta >> 1) as i32);
if !(0..64).contains(&scalefactor_test) {
return Err(HcaError::UnpackError("invalid scalefactor".into()));
}
value = value.wrapping_sub(expected_delta >> 1).wrapping_add(delta);
value &= 0x3F;
}
channel.scale_factors[i] = value;
}
} else {
channel.scale_factors[..HCA_SAMPLES_PER_SUBFRAME].fill(0);
}
for i in 0..extra_count {
channel.scale_factors[HCA_SAMPLES_PER_SUBFRAME - 1 - i] =
channel.scale_factors[cs_count - i];
}
Ok(())
}
fn unpack_intensity(&mut self, ch: usize, br: &mut BitReader) -> Result<(), HcaError> {
let channel = &mut self.channel[ch];
if channel.channel_type == ChannelType::StereoSecondary {
if self.version <= HCA_VERSION_200 {
let value = br.peek(4) as u8;
channel.intensity[0] = value;
if value < 15 {
br.skip(4);
for i in 1..HCA_SUBFRAMES {
channel.intensity[i] = br.read(4) as u8;
}
}
} else {
let value = br.peek(4) as u8;
if value < 15 {
br.skip(4);
let delta_bits = br.read(2) as u8;
channel.intensity[0] = value;
if delta_bits == 3 {
for i in 1..HCA_SUBFRAMES {
channel.intensity[i] = br.read(4) as u8;
}
} else {
let bmax = ((2 << delta_bits) - 1) as u8;
let bits = delta_bits + 1;
let mut value = value;
for i in 1..HCA_SUBFRAMES {
let delta = br.read(bits as usize) as u8;
if delta == bmax {
value = br.read(4) as u8;
} else {
value = value.wrapping_sub(bmax >> 1).wrapping_add(delta);
if value > 15 {
return Err(HcaError::UnpackError("invalid intensity".into()));
}
}
channel.intensity[i] = value;
}
}
} else {
br.skip(4);
channel.intensity.fill(7);
}
}
} else if self.version <= HCA_VERSION_200 {
let hfr_scales = &mut channel.scale_factors[128 - self.hfr_group_count as usize..];
for entry in hfr_scales.iter_mut().take(self.hfr_group_count as usize) {
*entry = br.read(6) as u8;
}
}
Ok(())
}
fn calculate_resolution(&mut self, ch: usize, packed_noise_level: u32) {
let channel = &mut self.channel[ch];
let cr_count = channel.coded_count;
let mut noise_count = 0usize;
let mut valid_count = 0usize;
for i in 0..cr_count {
let scalefactor = channel.scale_factors[i];
let mut new_resolution = 0u8;
if scalefactor > 0 {
let noise_level =
self.ath_curve[i] as i32 + ((packed_noise_level as i32 + i as i32) >> 8);
let curve_position = noise_level + 1 - ((5 * scalefactor as i32) >> 1);
if curve_position < 0 {
new_resolution = 15;
} else if curve_position <= 65 {
new_resolution = INVERT_TABLE[curve_position as usize];
} else {
new_resolution = 0;
}
if new_resolution > self.max_resolution as u8 {
new_resolution = self.max_resolution as u8;
} else if new_resolution < self.min_resolution as u8 {
new_resolution = self.min_resolution as u8;
}
if new_resolution < 1 {
channel.noises[noise_count] = i as u8;
noise_count += 1;
} else {
channel.noises[HCA_SAMPLES_PER_SUBFRAME - 1 - valid_count] = i as u8;
valid_count += 1;
}
}
channel.resolution[i] = new_resolution;
}
channel.noise_count = noise_count;
channel.valid_count = valid_count;
channel.resolution[cr_count..HCA_SAMPLES_PER_SUBFRAME].fill(0);
}
fn calculate_gain(&mut self, ch: usize) {
let channel = &mut self.channel[ch];
let cg_count = channel.coded_count;
for i in 0..cg_count {
let scalefactor_scale = DEQUANTIZER_SCALING_TABLE[channel.scale_factors[i] as usize];
let resolution_scale = DEQUANTIZER_RANGE_TABLE[channel.resolution[i] as usize];
channel.gain[i] = scalefactor_scale * resolution_scale;
}
}
fn dequantize_coefficients(&mut self, ch: usize, br: &mut BitReader, subframe: usize) {
let channel = &mut self.channel[ch];
let cc_count = channel.coded_count;
for i in 0..cc_count {
let resolution = channel.resolution[i];
let bits = MAX_BIT_TABLE[resolution as usize];
let code = br.read(bits as usize);
let qc: f32 = if resolution > 7 {
let sign = if (code & 1) != 0 { -1i32 } else { 1i32 };
let signed_code = sign * (code >> 1) as i32;
if signed_code == 0 {
br.set_position(br.position() - 1);
}
signed_code as f32
} else {
let index = ((resolution as usize) << 4) + code as usize;
let skip = READ_BIT_TABLE[index] as i32 - bits as i32;
if skip > 0 {
br.skip(skip as usize);
} else if skip < 0 {
br.set_position(br.position().saturating_sub((-skip) as usize));
}
READ_VAL_TABLE[index]
};
channel.spectra[subframe][i] = channel.gain[i] * qc;
}
channel.spectra[subframe][cc_count..HCA_SAMPLES_PER_SUBFRAME].fill(0.0);
}
fn decode_block_transform(&mut self) {
for subframe in 0..HCA_SUBFRAMES {
for ch in 0..self.channels as usize {
self.reconstruct_noise(ch, subframe);
self.reconstruct_high_frequency(ch, subframe);
}
if self.stereo_band_count > 0 {
for ch in 0..(self.channels as usize).saturating_sub(1) {
self.apply_intensity_stereo(ch, subframe);
self.apply_ms_stereo(ch, subframe);
}
}
for ch in 0..self.channels as usize {
imdct_transform(&mut self.channel[ch], subframe);
}
}
}
fn reconstruct_noise(&mut self, ch: usize, subframe: usize) {
if self.min_resolution > 0 {
return;
}
let channel = &self.channel[ch];
if channel.valid_count == 0 || channel.noise_count == 0 {
return;
}
if !(self.ms_stereo == 0 || channel.channel_type == ChannelType::StereoPrimary) {
return;
}
let mut r = self.random;
for i in 0..self.channel[ch].noise_count {
r = r.wrapping_mul(0x343FD).wrapping_add(0x269EC3);
let random_index = HCA_SAMPLES_PER_SUBFRAME - self.channel[ch].valid_count
+ (((r & 0x7FFF) as usize * self.channel[ch].valid_count) >> 15);
let noise_index = self.channel[ch].noises[i] as usize;
let valid_index = self.channel[ch].noises[random_index] as usize;
let sf_noise = self.channel[ch].scale_factors[noise_index];
let sf_valid = self.channel[ch].scale_factors[valid_index];
let sc_index = (sf_noise as i32 - sf_valid as i32 + 62).max(0) as usize;
let spectra_valid = self.channel[ch].spectra[subframe][valid_index];
self.channel[ch].spectra[subframe][noise_index] =
SCALE_CONVERSION_TABLE[sc_index] * spectra_valid;
}
self.random = r;
}
fn reconstruct_high_frequency(&mut self, ch: usize, subframe: usize) {
if self.bands_per_hfr_group == 0 {
return;
}
if self.channel[ch].channel_type == ChannelType::StereoSecondary {
return;
}
let start_band = (self.stereo_band_count + self.base_band_count) as usize;
let mut highband = start_band;
let mut lowband = start_band as i32 - 1;
let group_limit = if self.version <= HCA_VERSION_200 {
self.hfr_group_count as usize
} else {
(self.hfr_group_count as usize) >> 1
};
for group in 0..self.hfr_group_count as usize {
let lowband_sub: i32 = if group >= group_limit { 0 } else { 1 };
for _ in 0..self.bands_per_hfr_group as usize {
if highband >= self.total_band_count as usize || lowband < 0 {
break;
}
let hfr_scale =
self.channel[ch].scale_factors[128 - self.hfr_group_count as usize + group];
let sf_low = self.channel[ch].scale_factors[lowband as usize];
let sc_index = (hfr_scale as i32 - sf_low as i32 + 63).max(0) as usize;
let spectra_low = self.channel[ch].spectra[subframe][lowband as usize];
self.channel[ch].spectra[subframe][highband] =
SCALE_CONVERSION_TABLE[sc_index] * spectra_low;
highband += 1;
lowband -= lowband_sub;
}
}
if highband > 0 {
self.channel[ch].spectra[subframe][highband - 1] = 0.0;
}
}
fn apply_intensity_stereo(&mut self, ch: usize, subframe: usize) {
if self.channel[ch].channel_type != ChannelType::StereoPrimary {
return;
}
let ratio_l = INTENSITY_RATIO_TABLE[self.channel[ch + 1].intensity[subframe] as usize];
let ratio_r = 2.0 - ratio_l;
for band in self.base_band_count as usize..self.total_band_count as usize {
let coef = self.channel[ch].spectra[subframe][band];
self.channel[ch].spectra[subframe][band] = coef * ratio_l;
self.channel[ch + 1].spectra[subframe][band] = coef * ratio_r;
}
}
fn apply_ms_stereo(&mut self, ch: usize, subframe: usize) {
if self.ms_stereo == 0 {
return;
}
if self.channel[ch].channel_type != ChannelType::StereoPrimary {
return;
}
const RATIO: f32 = 0.707_106_77;
for band in self.base_band_count as usize..self.total_band_count as usize {
let l = self.channel[ch].spectra[subframe][band];
let r = self.channel[ch + 1].spectra[subframe][band];
self.channel[ch].spectra[subframe][band] = (l + r) * RATIO;
self.channel[ch + 1].spectra[subframe][band] = (l - r) * RATIO;
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc16_checksum() {
assert_eq!(crc16_checksum(&[]), 0);
let result = crc16_checksum(&[0x48, 0x43, 0x41, 0x00]);
assert_ne!(result, 0, "CRC of non-empty data should not be 0");
}
#[test]
fn test_header_ceil2() {
assert_eq!(header_ceil2(10, 3), 4);
assert_eq!(header_ceil2(9, 3), 3);
assert_eq!(header_ceil2(0, 3), 0);
assert_eq!(header_ceil2(10, 0), 0);
assert_eq!(header_ceil2(1, 1), 1);
assert_eq!(header_ceil2(7, 2), 4);
}
#[test]
fn test_is_hca_file_valid() {
let data = [0x48, 0x43, 0x41, 0x00, 0x01, 0x02, 0x00, 0x60];
let result = ClHca::is_hca_file(&data);
assert_eq!(result, Some(0x0060));
}
#[test]
fn test_is_hca_file_invalid() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
assert_eq!(ClHca::is_hca_file(&data), None);
let short = [0x48, 0x43];
assert_eq!(ClHca::is_hca_file(&short), None);
}
#[test]
fn test_clhca_new_defaults() {
let hca = ClHca::new();
assert!(!hca.is_valid);
assert_eq!(hca.version, 0);
assert_eq!(hca.channels, 0);
assert_eq!(hca.random, HCA_DEFAULT_RANDOM);
assert_eq!(hca.rva_volume, 1.0);
}
#[test]
fn test_clhca_clear() {
let mut hca = ClHca::new();
hca.version = 0x0102;
hca.channels = 2;
hca.clear();
assert_eq!(hca.version, 0);
assert_eq!(hca.channels, 0);
}
}