From 16dd4f445b3ee6b038926fdd2b9cd0081186eb28 Mon Sep 17 00:00:00 2001 From: Kostya Shishkov Date: Fri, 21 Sep 2018 19:21:17 +0200 Subject: [PATCH] RealAudio DNET decoder --- Cargo.toml | 3 +- src/codecs/mod.rs | 4 + src/codecs/ts102366.rs | 1485 ++++++++++++++++++++++++++++++++++++++++ src/register.rs | 2 +- 4 files changed, 1492 insertions(+), 2 deletions(-) create mode 100644 src/codecs/ts102366.rs diff --git a/Cargo.toml b/Cargo.toml index 7220927..7d34c53 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,8 +34,9 @@ decoder_realvideo2 = ["h263", "decoders"] decoder_realvideo3 = ["decoders"] decoder_realvideo4 = ["decoders"] -all_audio_decoders = ["decoder_pcm", "decoder_imc", "decoder_realaudio144", "decoder_realaudio288", "decoder_sipro"] +all_audio_decoders = ["decoder_pcm", "decoder_imc", "decoder_realaudio144", "decoder_realaudio288", "decoder_sipro", "decoder_ts102366"] decoder_pcm = ["decoders"] +decoder_ts102366 = ["decoders", "fft"] decoder_imc = ["decoders", "fft", "dsp_window"] decoder_realaudio144 = [] decoder_realaudio288 = [] diff --git a/src/codecs/mod.rs b/src/codecs/mod.rs index f06cf5a..c383357 100644 --- a/src/codecs/mod.rs +++ b/src/codecs/mod.rs @@ -253,6 +253,8 @@ mod real; mod pcm; #[cfg(feature="decoder_sipro")] mod sipro; +#[cfg(feature="decoder_ts102366")] +mod ts102366; const DECODERS: &[DecoderInfo] = &[ #[cfg(feature="decoder_clearvideo")] @@ -294,6 +296,8 @@ const DECODERS: &[DecoderInfo] = &[ DecoderInfo { name: "ra28.8", get_decoder: real::ra288::get_decoder }, #[cfg(feature="decoder_sipro")] DecoderInfo { name: "sipro", get_decoder: sipro::get_decoder }, +#[cfg(feature="decoder_ts102366")] + DecoderInfo { name: "ac3", get_decoder: ts102366::get_decoder }, ]; pub fn find_decoder(name: &str) -> Option Box> { diff --git a/src/codecs/ts102366.rs b/src/codecs/ts102366.rs new file mode 100644 index 0000000..8e9d75c --- /dev/null +++ b/src/codecs/ts102366.rs @@ -0,0 +1,1485 @@ +use formats::*; +use frame::*; +use super::*; +use io::bitreader::*; +use dsp::fft::*; +use std::str::FromStr; +use std::f32::consts; + +const BLOCK_LEN: usize = 256; +const NBLOCKS: usize = 6; +const MAX_CHANNELS: usize = 5; +const MAX_CPLBANDS: usize = 18; +const MAX_BANDS: usize = 50; + +const MAGIC_BYTE0: u8 = 0x0B; +const MAGIC_BYTE1: u8 = 0x77; + +const STRATEGY_REUSE: u8 = 0; + +const LFE_CHANNEL: usize = MAX_CHANNELS; +const CPL_CHANNEL: usize = MAX_CHANNELS + 1; + +struct IMDCTContext { + xsincos: [FFTComplex; BLOCK_LEN/2], + fft: FFT, + size: usize, +} + +struct IMDCTWorkspace { + z: [FFTComplex; BLOCK_LEN / 2], + y: [FFTComplex; BLOCK_LEN / 2], + out: [f32; BLOCK_LEN * 2], +} + +impl IMDCTContext { + fn new(bits: usize) -> Self { + let size = 1 << bits; + let size4 = 1 << (bits - 2); + let mut xsincos: [FFTComplex; 512/4] = [FFTC_ZERO; 512/4]; + for k in 0..size4 { + let factor = 2.0 * consts::PI * ((8 * k + 1) as f32) / ((8 * size) as f32); + xsincos[k].re = -factor.cos(); + xsincos[k].im = -factor.sin(); + } + let fft = FFTBuilder::new_fft(FFTMode::SplitRadix, size/4); + IMDCTContext { xsincos: xsincos, size: size, fft: fft } + } + #[allow(non_snake_case)] + fn do_imdct(&mut self, coeffs: &[i32; BLOCK_LEN], tmp: &mut IMDCTWorkspace) { + do_imdct_core(&mut self.fft, &self.xsincos, self.size, false, coeffs, &mut tmp.z, &mut tmp.y); + let w = &TS102366_WINDOW; + let N2 = self.size / 2; + let N4 = self.size / 4; + let N8 = self.size / 8; + for n in 0..N8 { + tmp.out[ 2 * n] = -tmp.y[N8 + n] .im * w[ 2 * n]; + tmp.out[ 2 * n + 1] = tmp.y[N8 - n - 1].re * w[ 2 * n + 1]; + tmp.out[ N4 + 2 * n] = -tmp.y[ n] .re * w[N4 + 2 * n]; + tmp.out[ N4 + 2 * n + 1] = tmp.y[N4 - n - 1].im * w[N4 + 2 * n + 1]; + tmp.out[ N2 + 2 * n] = -tmp.y[N8 + n] .re * w[N2 - 2 * n - 1]; + tmp.out[ N2 + 2 * n + 1] = tmp.y[N8 - n - 1].im * w[N2 - 2 * n - 2]; + tmp.out[3 * N4 + 2 * n] = tmp.y[ n] .im * w[N4 - 2 * n - 1]; + tmp.out[3 * N4 + 2 * n + 1] = -tmp.y[N4 - n - 1].re * w[N4 - 2 * n - 2]; + } + } + #[allow(non_snake_case)] + fn do_imdct_ileave(&mut self, coeffs: &[i32; BLOCK_LEN], tmp: &mut IMDCTWorkspace) { + let mut ziter = tmp.z.chunks_mut(self.size / 4); + let z1 = ziter.next().unwrap(); + let z2 = ziter.next().unwrap(); + let mut yiter = tmp.y.chunks_mut(self.size / 4); + let y1 = yiter.next().unwrap(); + let y2 = yiter.next().unwrap(); + do_imdct_core(&mut self.fft, &self.xsincos, self.size, true, coeffs, z1, y1); + do_imdct_core(&mut self.fft, &self.xsincos, self.size, true, &coeffs[1..], z2, y2); + let w = &TS102366_WINDOW; + let N2 = self.size / 2; + let N4 = self.size / 4; + let N8 = self.size / 8; + for n in 0..N8 { + tmp.out[ 2 * n] = -y1[ n] .im * w[ 2 * n]; + tmp.out[ 2 * n + 1] = y1[N8 - n - 1].re * w[ 2 * n + 1]; + tmp.out[ N4 + 2 * n] = -y1[ n] .re * w[N4 + 2 * n]; + tmp.out[ N4 + 2 * n + 1] = y1[N8 - n - 1].im * w[N4 + 2 * n + 1]; + tmp.out[ N2 + 2 * n] = -y2[ n] .re * w[N2 - 2 * n - 1]; + tmp.out[ N2 + 2 * n + 1] = y2[N8 - n - 1].im * w[N2 - 2 * n - 2]; + tmp.out[3 * N4 + 2 * n] = y2[ n] .im * w[N4 - 2 * n - 1]; + tmp.out[3 * N4 + 2 * n + 1] = -y2[N8 - n - 1].re * w[N4 - 2 * n - 2]; + } + } +} + +#[allow(non_snake_case)] +fn do_imdct_core(fft: &mut FFT, xsc: &[FFTComplex; BLOCK_LEN/2], size: usize, ilace: bool, coeffs: &[i32], z: &mut [FFTComplex], y: &mut [FFTComplex]) { + let N = size; + let N2 = size / 2; + let N4 = size / 4; + let scale = 1.0 / ((1 << 24) as f32); + for k in 0..N4 { + let (c0, c1) = if !ilace { + ((coeffs[N2 - 2 * k - 1] as f32) * scale , + (coeffs[ 2 * k] as f32) * scale) + } else { + ((coeffs[N - 4 * k - 2] as f32) * scale, + (coeffs[ 4 * k] as f32) * scale) + }; + z[k].re = c0 * xsc[k].re - c1 * xsc[k].im; + z[k].im = c0 * xsc[k].im + c1 * xsc[k].re; + } + fft.do_fft_inplace(z, false); + for k in 0..N4 { + y[k] = z[k] * xsc[k]; + } +} + +struct AudioDecoder { + info: Rc, + ablk: AudioBlock, + imdct512: IMDCTContext, + imdct256: IMDCTContext, + tmp: IMDCTWorkspace, + delay: [[f32; BLOCK_LEN]; MAX_CHANNELS + 1], +} + +impl AudioDecoder { + fn new() -> Self { + AudioDecoder { + info: NACodecInfo::new_dummy(), + ablk: AudioBlock::new(), + imdct512: IMDCTContext::new(9), + imdct256: IMDCTContext::new(8), + tmp: IMDCTWorkspace { + z: [FFTC_ZERO; BLOCK_LEN / 2], + y: [FFTC_ZERO; BLOCK_LEN / 2], + out: [0.0; BLOCK_LEN * 2], + }, + delay: [[0.0; BLOCK_LEN]; MAX_CHANNELS + 1], + } + } +} + +const SAMPLE_RATES: [u32; 4] = [ 48000, 44100, 32000, 0 ]; + +const FRAME_SIZES: [[usize; 64]; 4] = [ + [ + 64, 64, 80, 80, 96, 96, 112, 112, + 128, 128, 160, 160, 192, 192, 224, 224, + 256, 256, 320, 320, 384, 384, 448, 448, + 512, 512, 640, 640, 768, 768, 896, 896, + 1024, 1024, 1152, 1152, 1280, 1280, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], [ + 69, 70, 87, 88, 104, 105, 121, 122, + 139, 140, 174, 175, 208, 209, 243, 244, + 278, 279, 348, 349, 417, 418, 487, 488, + 557, 558, 696, 697, 835, 836, 975, 976, + 1114, 1115, 1253, 1254, 1393, 1394, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], [ + 96, 96, 120, 120, 144, 144, 168, 168, + 192, 192, 240, 240, 288, 288, 336, 336, + 384, 384, 480, 480, 576, 576, 672, 672, + 768, 768, 960, 960, 1152, 1152, 1344, 1344, + 1536, 1536, 1728, 1728, 1920, 1920, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], [ 0; 64 ], +]; + +#[derive(Debug,Clone,Copy)] +struct Syncinfo { + crc1: u16, + fscod: u8, + frmsizecod: u8, + samplerate: u32, + frame_size: usize, +} + +impl Syncinfo { + fn read(br: &mut BitReader) -> DecoderResult { + let syncword = br.read(16)?; + validate!(syncword == ((MAGIC_BYTE0 as u32) * 256) + (MAGIC_BYTE1 as u32)); + let crc1 = br.read(16)? as u16; + let fscod = br.read(2)? as usize; + let frmsizecod = br.read(6)? as usize; + Ok(Syncinfo { crc1: crc1, fscod: fscod as u8, frmsizecod: frmsizecod as u8, + samplerate: SAMPLE_RATES[fscod], frame_size: FRAME_SIZES[fscod][frmsizecod] * 2 }) + } + fn is_valid(&self) -> bool { + (self.samplerate != 0) && (self.frame_size != 0) + } +} + +trait ReadOptional { + fn read_optional8(&mut self) -> BitReaderResult>; + fn read_optional16(&mut self, bits: u8) -> BitReaderResult>; +} + +impl<'a> ReadOptional for BitReader<'a> { + fn read_optional8(&mut self) -> BitReaderResult> { + if self.read_bool()? { + Ok(Some(self.read(8)? as u8)) + } else { + Ok(None) + } + } + fn read_optional16(&mut self, bits: u8) -> BitReaderResult> { + if self.read_bool()? { + Ok(Some(self.read(bits)? as u16)) + } else { + Ok(None) + } + } +} + +#[derive(Debug,Clone,Copy,PartialEq)] +enum ACMode { + DualMono, + Mono, + Stereo, + Mode3_0, + Mode2_1, + Mode3_1, + Mode2_2, + Mode3_2, +} + +impl ACMode { + fn get_num_channels(&self) -> usize { + match *self { + ACMode::DualMono => 2, + ACMode::Mono => 1, + ACMode::Stereo => 2, + ACMode::Mode3_0 => 3, + ACMode::Mode2_1 => 3, + ACMode::Mode3_1 => 4, + ACMode::Mode2_2 => 4, + ACMode::Mode3_2 => 5, + } + } + fn get_channel_map_str(&self) -> &'static str { + match *self { + ACMode::DualMono => "C,C", + ACMode::Mono => "C", + ACMode::Stereo => "L,R", + ACMode::Mode3_0 => "L,C,R", + ACMode::Mode2_1 => "L,R,Cs", + ACMode::Mode3_1 => "L,C,R,Cs", + ACMode::Mode2_2 => "L,R,Ls,Rs", + ACMode::Mode3_2 => "L,C,R,Ls,Rs", + } + } + fn get_channel_map(&self, has_lfe: bool) -> NAChannelMap { + let mut chmap = NAChannelMap::from_str(self.get_channel_map_str()).unwrap(); + if has_lfe { + chmap.add_channel(NAChannelType::LFE); + } + chmap + } + fn is_3_x(&self) -> bool { + match *self { + ACMode::Mode3_0 | + ACMode::Mode3_1 | + ACMode::Mode3_2 => true, + _ => false, + } + } + fn is_surround(&self) -> bool { + match *self { + ACMode::Mode2_1 | + ACMode::Mode3_1 | + ACMode::Mode2_2 | + ACMode::Mode3_2 => true, + _ => false, + } + } +} + +const AC_MODES: [ACMode; 8] = [ + ACMode::DualMono, ACMode::Mono, ACMode::Stereo, + ACMode::Mode3_0, ACMode::Mode2_1, + ACMode::Mode3_1, ACMode::Mode2_2, + ACMode::Mode3_2 +]; + +#[derive(Debug,Clone,Copy)] +struct Mixinfo { + dialnorm: u8, + compr: Option, + langcod: Option, + mixlevel: Option, + roomtyp: Option, +} + +impl Mixinfo { + fn read(br: &mut BitReader) -> DecoderResult { + let dialnorm = br.read(5)? as u8; + let compr = br.read_optional8()?; + let langcod = br.read_optional8()?; + let (mixlevel, roomtyp) = if br.read_bool()? { + let mlev = br.read(5)? as u8; + let rt = br.read(2)? as u8; + validate!(rt < 3); + (Some(mlev), Some(rt)) + } else { + (None, None) + }; + Ok(Mixinfo { dialnorm, compr, langcod, mixlevel, roomtyp }) + } +} + +#[derive(Debug,Clone,Copy)] +struct BSI { + bsid: u8, + shift: u8, + bsmod: u8, + acmod: ACMode, + cmixlev: Option, + surmixlev: Option, + dsurmod: Option, + lfeon: bool, + mixinfo: Mixinfo, + mixinfo2: Option, + copysmth: bool, + origbs: bool, + timecod1: Option, + timecod2: Option, + has_addb: bool, +} + +impl BSI { + fn read(br: &mut BitReader) -> DecoderResult { + let bsid = br.read(5)? as u8; + validate!(bsid <= 10); + let shift = if bsid < 9 { 0 } else { bsid - 9 + 1 }; + let bsmod = br.read(3)? as u8; + let acmod_id = br.read(3)? as usize; + validate!(acmod_id < AC_MODES.len()); + let acmod = AC_MODES[acmod_id]; + let cmixlev = if acmod.is_3_x() { + let cl = br.read(2)? as u8; + validate!(cl < 3); + Some(cl) + } else { None }; + let surmixlev = if acmod.is_surround() { + let sml = br.read(2)? as u8; + validate!(sml < 3); + Some(sml) + } else { None }; + let dsurmod = if acmod == ACMode::Stereo { + let dsm = br.read(2)? as u8; + validate!(dsm < 3); + Some(dsm) + } else { None }; + let lfeon = br.read_bool()?; + let mixinfo = Mixinfo::read(br)?; + let mixinfo2 = if acmod == ACMode::DualMono { + Some(Mixinfo::read(br)?) + } else { + None + }; + let copysmth = br.read_bool()?; + let origbs = br.read_bool()?; + let timecod1 = br.read_optional16(14)?; + let timecod2 = br.read_optional16(14)?; + let has_addb = br.read_bool()?; + Ok(BSI{ + bsid, shift, bsmod, acmod, lfeon, + cmixlev, surmixlev, dsurmod, + mixinfo: mixinfo, mixinfo2: mixinfo2, + copysmth, origbs, timecod1, timecod2, has_addb, + }) + } +} + +#[derive(Clone, Copy)] +struct ChannelData { + blksw: bool, + dithflag: bool, + + chincpl: bool, + cplcoe: bool, + cplcoexp: [u8; MAX_CPLBANDS], + cplcomant: [u8; MAX_CPLBANDS], + mstrcplco: u8, + + chbwcod: u8, + + expstr: u8, + gainrng: u8, + startmant: usize, + endmant: usize, + groups: usize, + + fsnroffst: u8, + fgaincod: usize, + snroffset: i32, + + deltbae: u8, + deltnseg: usize, + deltoffst: [u8; 8], + deltlen: [usize; 8], + deltba: [u8; 8], + + bap: [u8; 256], + exps: [u8; 256], + mant: [i32; 256], + + psd: [i16; 256], + bndpsd: [i32; 64], +} + +const GROUPS: [usize; 4] = [ 0, 3, 6, 12 ]; +const GROUP_BIAS: [usize; 4] = [ 0, 0, 3, 9 ]; + +fn decode_exps(br: &mut BitReader, dst: &mut [u8], mut prev: u8, grplen: usize) -> DecoderResult<()> { + let repeat = grplen / 3; + + for out in dst.chunks_mut(grplen) { + let val = br.read(7)? as u8; + validate!(val < 125); + let diff: [u8; 3] = [ val / 25, (val / 5) % 5, val % 5 ]; + for (i, exps) in out.chunks_mut(repeat).enumerate() { + exps[0] = (prev + diff[i]).wrapping_sub(2); + validate!(exps[0] <= 24); + for j in 1..repeat { + exps[j] = exps[0]; + } + prev = exps[0]; + } + } + + Ok(()) +} + +macro_rules! read_bap { + ($br: expr, $tab:ident, $nbits:expr) => ({ + let val = $br.read($nbits)? as usize; + validate!(val < $tab.len()); + $tab[val] + }); + ($br:expr, $tab:ident, $nbits:expr, $bufidx:expr, $bap_buf:expr, $bap_buf_fill:expr) => ( + if $bap_buf_fill[$bufidx] > 0 { + $bap_buf_fill[$bufidx] -= 1; + $bap_buf[$bufidx][$bap_buf_fill[$bufidx]] + } else { + let val = $br.read($nbits)? as usize; + validate!(val < $tab.len()); + for i in 1..$tab[0].len() { + $bap_buf[$bufidx][i - 1] = $tab[val][i]; + } + $bap_buf_fill[$bufidx] = $tab[0].len() - 1; + $tab[val][0] + } + ); +} + +impl ChannelData { + fn new() -> Self { + ChannelData { + blksw: false, + dithflag: false, + + chincpl: false, + cplcoe: false, + cplcoexp: [0; MAX_CPLBANDS], + cplcomant: [0; MAX_CPLBANDS], + mstrcplco: 0, + + chbwcod: 0, + + expstr: 0, + gainrng: 0, + startmant: 0, + endmant: 0, + groups: 0, + + fsnroffst: 0, + fgaincod: 0, + snroffset: 0, + + deltbae: 0, + deltnseg: 0, + deltoffst: [0; 8], + deltlen: [0; 8], + deltba: [0; 8], + + bap: [0; 256], + exps: [0; 256], + mant: [0; 256], + + psd: [0; 256], + bndpsd: [0; 64], + } + } + fn read_strategy(&mut self, br: &mut BitReader, blk_no: usize) -> DecoderResult<()> { + self.expstr = br.read(2)? as u8; + validate!(blk_no != 0 || self.expstr != STRATEGY_REUSE); + if self.expstr != STRATEGY_REUSE { + if self.startmant > 0 { + self.groups = (self.endmant - self.startmant) / GROUPS[self.expstr as usize]; + } else if self.endmant != 0{ + let idx = self.expstr as usize; + self.groups = (self.endmant + GROUP_BIAS[idx] - 1) / GROUPS[idx]; + } else { + self.groups = 0; + } + } + Ok(()) + } + fn read_exps(&mut self, br: &mut BitReader, is_cpl: bool, is_lfe: bool) -> DecoderResult<()> { + if self.expstr == STRATEGY_REUSE { return Ok(()); } + let grpsize = GROUPS[self.expstr as usize]; + self.exps = [0; 256]; + if is_cpl { + let first = (br.read(4)? as u8) << 1; + let out = &mut self.exps[self.startmant..self.endmant]; + decode_exps(br, out, first, grpsize)?; + } else if !is_lfe { + self.exps[0] = br.read(4)? as u8; + let first = self.exps[0]; + let out = &mut self.exps[1..self.endmant]; + decode_exps(br, out, first, grpsize)?; + self.gainrng = br.read(2)? as u8; + } else { + self.exps[0] = br.read(4)? as u8; + let first = self.exps[0]; + let out = &mut self.exps[1..7]; + decode_exps(br, out, first, grpsize)?; + } + Ok(()) + } + fn read_snr(&mut self, br: &mut BitReader) -> DecoderResult<()> { + self.fsnroffst = br.read(4)? as u8; + self.fgaincod = br.read(3)? as usize; + Ok(()) + } + fn read_deltbai(&mut self, br: &mut BitReader) -> DecoderResult<()> { + if self.deltbae == 1 { + self.deltnseg = (br.read(3)? as usize) + 1; + for seg in 0..self.deltnseg { + self.deltoffst[seg] = br.read(5)? as u8; + self.deltlen[seg] = br.read(4)? as usize; + self.deltba[seg] = br.read(3)? as u8; + } + } + Ok(()) + } + + fn compute_bndpsd(&mut self) { + let start = self.startmant; + let end = self.endmant; + let exps = &mut self.exps; + let psd = &mut self.psd; + let bndpsd = &mut self.bndpsd; + + for bin in start..end { + psd[bin] = 3072 - ((exps[bin] as i16) << 7); + } + + let mut bin = start; + let mut band = TS102366_BIN_TO_BAND[bin] as usize; + let mut lastbin; + loop { + lastbin = ((TS102366_BAND_START[band] as usize) + (TS102366_BAND_SIZE[band] as usize)).min(end); + bndpsd[band] = psd[bin] as i32; + bin += 1; + while bin < lastbin { + bndpsd[band] = logadd(bndpsd[band], psd[bin] as i32); + bin += 1; + } + band += 1; + if lastbin >= end { break; } + } + } + fn compute_mask(&mut self, mask: &mut [i32; MAX_BANDS], fscod: usize, sgain: u16, fdecay: u8, sdecay: u8, + dbknee: u16, cplfleak: u16, cplsleak: u16, shift: u8) { + let fgain = TS102366_FAST_GAIN[self.fgaincod] as i32; + + let bndstart = TS102366_BIN_TO_BAND[self.startmant] as usize; + let bndend = (TS102366_BIN_TO_BAND[self.endmant - 1] as usize) + 1; + + let mut excite: [i32; MAX_BANDS] = [0; MAX_BANDS]; + + let begin; + let mut fast_leak; + let mut slow_leak; + if bndstart == 0 { + let lowcomp0 = calc_lowcomp(0, self.bndpsd[0], self.bndpsd[1], 0); + excite[0] = self.bndpsd[0] - fgain - lowcomp0; + let lowcomp1 = calc_lowcomp(lowcomp0, self.bndpsd[1], self.bndpsd[2], 1); + excite[1] = self.bndpsd[1] - fgain - lowcomp1; + let mut sband = 7; + let mut lowcomp = lowcomp1; + fast_leak = 0; + slow_leak = 0; + for band in 2..7 { + let not_lfe_case = (bndend != 7) || (band != 6); + if not_lfe_case { + lowcomp = calc_lowcomp(lowcomp, self.bndpsd[band], self.bndpsd[band + 1], band); + } + fast_leak = self.bndpsd[band] - fgain; + slow_leak = self.bndpsd[band] - (sgain as i32); + excite[band] = fast_leak - lowcomp; + if not_lfe_case { + if self.bndpsd[band] <= self.bndpsd[band + 1] { + sband = band + 1; + break; + } + } + } + for band in sband..bndend.min(22) { + if (bndend != 7) || (band != 6) { + lowcomp = calc_lowcomp(lowcomp, self.bndpsd[band], self.bndpsd[band + 1], band); + } + fast_leak = (fast_leak - (fdecay as i32)).max(self.bndpsd[band] - (fgain as i32)); + slow_leak = (slow_leak - (sdecay as i32)).max(self.bndpsd[band] - (sgain as i32)); + excite[band] = slow_leak.max(fast_leak - lowcomp); + } + begin = 22; + } else { + begin = bndstart; + fast_leak = cplfleak as i32; + slow_leak = cplsleak as i32; + } + for band in begin..bndend { + fast_leak = (fast_leak - (fdecay as i32)).max(self.bndpsd[band] - (fgain as i32)); + slow_leak = (slow_leak - (sdecay as i32)).max(self.bndpsd[band] - (sgain as i32)); + excite[band] = fast_leak.max(slow_leak); + } + for band in bndstart..bndend { + if self.bndpsd[band] < (dbknee as i32) { + excite[band] += ((dbknee as i32) - self.bndpsd[band]) >> 2; + } + mask[band] = excite[band].max(TS102366_HTH[fscod][band >> shift] as i32); + } + } + fn apply_delta_info(&mut self, mask: &mut [i32; MAX_BANDS]) { + if self.deltbae == 0 || self.deltbae == 1 { + let mut band = TS102366_BIN_TO_BAND[self.startmant] as usize; + for seg in 0..self.deltnseg { + band += self.deltoffst[seg] as usize; + let delta = if self.deltba[seg] >= 4 { + ((self.deltba[seg] as i32) - 3) << 7 + } else { + ((self.deltba[seg] as i32) - 4) << 7 + }; + if band + self.deltlen[seg] > MAX_BANDS { break; } + for _ in 0..self.deltlen[seg] { + mask[band] += delta; + band += 1; + } + } + } + } + fn calc_snr_offset(&mut self, csnroffst: u8) { + self.snroffset = ((((csnroffst as i32) - 15) << 4) + (self.fsnroffst as i32)) << 2; + } + fn compute_bap(&mut self, mask: &mut [i32; MAX_BANDS], floor: u16) { + let end = self.endmant; + let mut band = TS102366_BIN_TO_BAND[self.startmant] as usize; + let mut bin = self.startmant; + let mut lastbin; + loop { + lastbin = ((TS102366_BAND_START[band] as usize) + (TS102366_BAND_SIZE[band] as usize)).min(end); + mask[band] = (mask[band] - self.snroffset - (floor as i32)).max(0) & 0x1FE0; + mask[band] += floor as i32; + while bin < lastbin { + let addr = (((self.psd[bin] as i32) - mask[band]) >> 5).min(63).max(0) as usize; + self.bap[bin] = TS102366_BAPTAB[addr]; + bin += 1; + } + if lastbin == end { break; } + band += 1; + } + } + fn read_mant(&mut self, br: &mut BitReader, bap_buf: &mut [[i32; 2]; 3], bap_buf_fill: &mut [usize; 3]) -> DecoderResult<()> { + self.mant = [0; BLOCK_LEN]; + for bin in self.startmant..self.endmant { + self.mant[bin] = match self.bap[bin] { + 0 => { + if self.dithflag { + 42 // todo dither + } else { + 0 + } + }, + 1 => { read_bap!(br, TS102366_QUANT3_MAP, 5, 0, bap_buf, bap_buf_fill) }, + 2 => { read_bap!(br, TS102366_QUANT5_MAP, 7, 1, bap_buf, bap_buf_fill) }, + 3 => { read_bap!(br, TS102366_QUANT7_MAP, 3) }, + 4 => { read_bap!(br, TS102366_QUANT11_MAP, 7, 2, bap_buf, bap_buf_fill) }, + 5 => { read_bap!(br, TS102366_QUANT15_MAP, 4) }, + _ => { + validate!(self.bap[bin] < 15); + let nbits = TS102366_BAP_BITS[(self.bap[bin] as usize) - 6]; + let val = br.read(nbits)? as i16; + ((val << (16 - nbits)) as i32) << 9 + }, + }; + self.mant[bin] >>= self.exps[bin]; + } + Ok(()) + } + + fn synth(&mut self, imdct512: &mut IMDCTContext, imdct256: &mut IMDCTContext, tmp: &mut IMDCTWorkspace, delay: &mut [f32; BLOCK_LEN], dst: &mut [f32]) { + if !self.blksw { + imdct512.do_imdct(&self.mant, tmp); + } else { + imdct256.do_imdct_ileave(&self.mant, tmp); + } + overlap(delay, &tmp.out, dst); + } +} + +fn logadd(acc: i32, add: i32) -> i32 { + let c = acc - add; + let addr = (c.abs() >> 1).min(255); + if c >= 0 { + acc + (TS102366_LATAB[addr as usize] as i32) + } else { + add + (TS102366_LATAB[addr as usize] as i32) + } +} + +fn calc_lowcomp(a: i32, b0: i32, b1: i32, band: usize) -> i32 { + if band < 7 { + if (b0 + 256) == b1 { + 384 + } else if b0 > b1 { + 0.max(a - 64) + } else { + a + } + } else if band < 20 { + if (b0 + 256) == b1 { + 320 + } else if b0 > b1 { + 0.max(a - 64) + } else { + a + } + } else { + 0.max(a - 128) + } +} + +fn overlap(delay: &mut [f32; BLOCK_LEN], src: &[f32; BLOCK_LEN * 2], out: &mut [f32]) { + { + let dly = &delay; + for ((d, s), o) in dly.into_iter().zip(src.into_iter()).zip(out.iter_mut()) { + *o = (*d + *s) * 2.0; + } + } + delay.copy_from_slice(&src[BLOCK_LEN..]); +} + +#[derive(Clone)] +struct AudioBlock { + dynrng: Option, + dynrng2: Option, + + cplstre: bool, + cplinu: bool, + phsflginu: bool, + cplbegf: usize, + cplendf: usize, + ncplsubnd: usize, + ncplbnd: usize, + cplbndstrc: [bool; MAX_CPLBANDS], + + phsflg: [bool; MAX_CPLBANDS], + rematstr: bool, + rematflg: [bool; 4], + + chdata: [ChannelData; MAX_CHANNELS + 2], + + baie: bool, + fdcycod: usize, + sdcycod: usize, + sgaincod: usize, + dbpbcod: usize, + floorcod: usize, + snroffste: bool, + csnroffst: u8, + cplleake: bool, + cplfleak: u8, + cplsleak: u8, + + deltbaie: bool, + + bap_buf: [[i32; 2]; 3], + bap_buf_fill: [usize; 3], +} + +impl AudioBlock { + fn new() -> Self { + AudioBlock { + chdata: [ChannelData::new(); MAX_CHANNELS + 2], + + dynrng: None, + dynrng2: None, + + cplstre: false, + cplinu: false, + phsflginu: false, + cplbegf: 0, + cplendf: 0, + ncplsubnd: 0, + ncplbnd: 0, + cplbndstrc: [false; MAX_CPLBANDS], + + phsflg: [false; MAX_CPLBANDS], + rematstr: false, + rematflg: [false; 4], + + baie: false, + sdcycod: 0, + fdcycod: 0, + sgaincod: 0, + dbpbcod: 0, + floorcod: 0, + snroffste: false, + csnroffst: 0, + cplleake: false, + cplfleak: 0, + cplsleak: 0, + + deltbaie: false, + + bap_buf: [[0; 2]; 3], + bap_buf_fill: [0; 3], + } + } + fn read(&mut self, br: &mut BitReader, bsi: &BSI, fscod: usize, blk_no: usize) -> DecoderResult { + let channels = bsi.acmod.get_num_channels(); + let is_stereo = bsi.acmod == ACMode::Stereo; + + for ch in 0..channels { + self.chdata[ch].blksw = br.read_bool()?; + } + // dynamic range information + for ch in 0..channels { + self.chdata[ch].dithflag = br.read_bool()?; + } + self.dynrng = br.read_optional8()?; + if bsi.acmod == ACMode::DualMono { + self.dynrng2 = br.read_optional8()?; + } + // coupling strategy information + self.cplstre = br.read_bool()?; + validate!((blk_no != 0) || self.cplstre); + if self.cplstre { + self.cplinu = br.read_bool()?; + if self.cplinu { + for ch in 0..channels { + self.chdata[ch].chincpl = br.read_bool()?; + } + if is_stereo { + self.phsflginu = br.read_bool()?; + } + self.cplbegf = br.read(4)? as usize; + self.cplendf = (br.read(4)? as usize) + 3; + validate!(self.cplendf >= self.cplbegf); + self.ncplsubnd = self.cplendf - self.cplbegf; + self.ncplbnd = self.ncplsubnd; + self.chdata[CPL_CHANNEL].startmant = self.cplbegf * 12 + 37; + self.chdata[CPL_CHANNEL].endmant = self.cplendf * 12 + 37; + for bnd in 1..self.ncplsubnd { + self.cplbndstrc[bnd] = br.read_bool()?; + if self.cplbndstrc[bnd] { + self.ncplbnd -= 1; + } + } + } + } + // coupling coordinates + if self.cplinu { + for c in 0..channels { + let ch = &mut self.chdata[c]; + if ch.chincpl { + ch.cplcoe = br.read_bool()?; + if ch.cplcoe { + ch.mstrcplco = br.read(2)? as u8; + for bnd in 0..self.ncplbnd { + ch.cplcoexp [bnd] = br.read(4)? as u8; + ch.cplcomant[bnd] = br.read(4)? as u8; + } + } + } + } + if is_stereo && self.phsflginu && (self.chdata[0].cplcoe || self.chdata[1].cplcoe) { + for bnd in 0..self.ncplbnd { + self.phsflg[bnd] = br.read_bool()?; + } + } + } + // stereo rematrixing + if is_stereo { + self.rematstr = br.read_bool()?; + if self.rematstr { + if self.cplbegf > 2 || !self.cplinu { + for rbnd in 0..4 { + self.rematflg[rbnd] = br.read_bool()?; + } + } + if self.cplbegf > 0 && self.cplbegf <= 2 && self.cplinu { + for rbnd in 0..3 { + self.rematflg[rbnd] = br.read_bool()?; + } + } + if self.cplbegf == 0 && self.cplinu { + for rbnd in 0..2 { + self.rematflg[rbnd] = br.read_bool()?; + } + } + } + } + // exponent strategy + if self.cplinu { + self.chdata[CPL_CHANNEL].read_strategy(br, blk_no)?; + } + for ch in 0..channels { + self.chdata[ch].read_strategy(br, blk_no)?; + } + if bsi.lfeon { + self.chdata[LFE_CHANNEL].expstr = br.read(1)? as u8; + validate!(blk_no != 0 || self.chdata[LFE_CHANNEL].expstr != STRATEGY_REUSE); + self.chdata[LFE_CHANNEL].groups = 2; + self.chdata[LFE_CHANNEL].startmant = 0; + self.chdata[LFE_CHANNEL].endmant = 7; + } + let cpl_startmant = self.chdata[CPL_CHANNEL].startmant; + for c in 0..channels { + let ch = &mut self.chdata[c]; + if ch.expstr != STRATEGY_REUSE && !ch.chincpl { + ch.chbwcod = br.read(6)? as u8; + } + if !ch.chincpl { + ch.startmant = 0; + ch.endmant = ((ch.chbwcod as usize) + 12) * 3 + 37; + } else { + ch.startmant = 0; + ch.endmant = cpl_startmant; + } + } + // set number of mantissas + if self.cplinu { + self.chdata[CPL_CHANNEL].read_exps(br, true, false)?; + } + for ch in 0..channels { + self.chdata[ch].read_exps(br, false, false)?; + } + if bsi.lfeon { + self.chdata[LFE_CHANNEL].read_exps(br, false, true)?; + } + // bit allocation parameters + self.baie = br.read_bool()?; + if self.baie { + self.sdcycod = br.read(2)? as usize; + self.fdcycod = br.read(2)? as usize; + self.sgaincod = br.read(2)? as usize; + self.dbpbcod = br.read(2)? as usize; + self.floorcod = br.read(3)? as usize; + } + self.snroffste = br.read_bool()?; + if self.snroffste { + self.csnroffst = br.read(6)? as u8; + if self.cplinu { + self.chdata[CPL_CHANNEL].read_snr(br)?; + } + for ch in 0..channels { + self.chdata[ch].read_snr(br)?; + } + if bsi.lfeon { + self.chdata[LFE_CHANNEL].read_snr(br)?; + } + } + if self.cplinu { + self.cplleake = br.read_bool()?; + if self.cplleake { + self.cplfleak = br.read(3)? as u8; + self.cplsleak = br.read(3)? as u8; + } + } + // delta bit allocation information + self.deltbaie = br.read_bool()?; + if self.deltbaie { + if self.cplinu { + self.chdata[CPL_CHANNEL].deltbae = br.read(2)? as u8; + validate!(blk_no != 0 || self.chdata[CPL_CHANNEL].deltbae != 0); + validate!(self.chdata[CPL_CHANNEL].deltbae != 3); + } + for ch in 0..channels { + self.chdata[ch].deltbae = br.read(2)? as u8; + validate!(blk_no != 0 || self.chdata[ch].deltbae != 0); + validate!(self.chdata[ch].deltbae != 3); + } + if self.cplinu { + self.chdata[CPL_CHANNEL].read_deltbai(br)?; + } + for ch in 0..channels { + self.chdata[ch].read_deltbai(br)?; + } + } + // dummy data + if br.read_bool()? { + let skipl = br.read(9)?; + br.skip(skipl * 8)?; + } + + let all_zero = self.calc_bitalloc(bsi, channels, fscod); + if all_zero { return Ok(true); } + + // quantised mantissa values + let mut got_cplchan = false; + for i in 0..self.bap_buf_fill.len() { self.bap_buf_fill[i] = 0; } + for c in 0..channels { + { + let ch = &mut self.chdata[c]; + ch.read_mant(br, &mut self.bap_buf, &mut self.bap_buf_fill)?; + } + if self.cplinu && self.chdata[c].chincpl && !got_cplchan { + let cplch = &mut self.chdata[CPL_CHANNEL]; + cplch.read_mant(br, &mut self.bap_buf, &mut self.bap_buf_fill)?; + got_cplchan = true; + } + } + if bsi.lfeon { + let lfech = &mut self.chdata[LFE_CHANNEL]; + lfech.read_mant(br, &mut self.bap_buf, &mut self.bap_buf_fill)?; + } + Ok(false) + } + fn calc_bitalloc(&mut self, bsi: &BSI, channels: usize, fscod: usize) -> bool { + let sdecay1 = TS102366_SLOW_DECAY[self.sdcycod]; + let fdecay1 = TS102366_FAST_DECAY[self.fdcycod]; + + let sdecay = sdecay1 >> bsi.shift; + let fdecay = fdecay1 >> bsi.shift; + let sgain = TS102366_SLOW_GAIN[self.sgaincod]; + let dbknee = TS102366_DBP_TAB[self.dbpbcod]; + let floor = TS102366_FLOOR_TAB[self.floorcod]; + + let mut all_zero = self.csnroffst == 0; + if !all_zero && self.chdata[LFE_CHANNEL].fsnroffst == 0 { + for ch in 0..channels { + if self.chdata[ch].fsnroffst != 0 { + all_zero = false; + break; + } + } + } + if all_zero { return true; } + + let mut mask: [i32; MAX_BANDS] = [0; MAX_BANDS]; + + if self.cplinu { + self.chdata[CPL_CHANNEL].compute_bndpsd(); + self.chdata[CPL_CHANNEL].compute_mask(&mut mask, fscod, sgain, fdecay, sdecay, dbknee, + ((self.cplfleak as u16) << 8) + 768, ((self.cplsleak as u16) << 8) + 768, bsi.shift); + self.chdata[CPL_CHANNEL].apply_delta_info(&mut mask); + self.chdata[CPL_CHANNEL].calc_snr_offset(self.csnroffst); + self.chdata[CPL_CHANNEL].compute_bap(&mut mask, floor); + } + for ch in 0..channels { + self.chdata[ch].compute_bndpsd(); + self.chdata[ch].compute_mask(&mut mask, fscod, sgain, fdecay, sdecay, dbknee, 0, 0, bsi.shift); + self.chdata[ch].apply_delta_info(&mut mask); + self.chdata[ch].calc_snr_offset(self.csnroffst); + self.chdata[ch].compute_bap(&mut mask, floor); + } + if bsi.lfeon { + self.chdata[LFE_CHANNEL].compute_bndpsd(); + self.chdata[LFE_CHANNEL].compute_mask(&mut mask, fscod, sgain, fdecay, sdecay, dbknee, + 0, 0, bsi.shift); + self.chdata[LFE_CHANNEL].calc_snr_offset(self.csnroffst); + self.chdata[LFE_CHANNEL].compute_bap(&mut mask, floor); + } + + false + } + fn couple_channels(&mut self, acmod: ACMode) { + if !self.cplinu { return; } + for ch in 0..acmod.get_num_channels() { + if !self.chdata[ch].chincpl { continue; } + let mut pband = 0; + for band in self.cplbegf..self.cplendf { + let cband = band - self.cplbegf; + let comant = self.chdata[ch].cplcomant[cband]; + let mut cotemp = (if self.chdata[ch].cplcoexp[cband] == 15 { comant << 1 } else { comant + 16 }) as i32; + if (acmod == ACMode::Stereo) && (ch == 1) && self.phsflginu && self.phsflg[pband] { + cotemp = -cotemp; + } + if !self.cplbndstrc[cband] { + pband += 1; + } + let exp = self.chdata[ch].cplcoexp[cband] + 3 * self.chdata[ch].mstrcplco + 5 - 3; + let start = band * 12 + 37; + for bin in 0..12 { + self.chdata[ch].mant[start + bin] = self.chdata[CPL_CHANNEL].mant[start + bin] * cotemp >> exp; + } +//todo dither + } + } + } + fn synth_audio_block(&mut self, imdct512: &mut IMDCTContext, imdct256: &mut IMDCTContext, tmp: &mut IMDCTWorkspace, channel: usize, delay: &mut [f32; BLOCK_LEN], dst: &mut [f32]) { + self.chdata[channel].synth(imdct512, imdct256, tmp, delay, dst); + } +} + +impl NADecoder for AudioDecoder { + fn init(&mut self, info: Rc) -> DecoderResult<()> { + if let NACodecTypeInfo::Audio(_) = info.get_properties() { + self.info = info.clone(); + Ok(()) + } else { + Err(DecoderError::InvalidData) + } + } + fn decode(&mut self, pkt: &NAPacket) -> DecoderResult { + let info = pkt.get_stream().get_info(); + validate!(info.get_properties().is_audio()); + let pktbuf = pkt.get_buffer(); + validate!(pktbuf.len() > 5); + + let mut br; + if (pktbuf[0] == MAGIC_BYTE0) && (pktbuf[1] == MAGIC_BYTE1) { + br = BitReader::new(pktbuf.as_slice(), pktbuf.len(), BitReaderMode::BE); + } else if (pktbuf[0] == MAGIC_BYTE1) && (pktbuf[1] == MAGIC_BYTE0) { + br = BitReader::new(pktbuf.as_slice(), pktbuf.len(), BitReaderMode::LE16MSB); + } else { + return Err(DecoderError::InvalidData); + } + + let sinfo = Syncinfo::read(&mut br)?; + validate!(sinfo.is_valid()); + + let bsi = BSI::read(&mut br)?; + if bsi.has_addb { + let len = br.read(6)? as u32; + br.skip((len + 1) * 8)?; + } + + let duration = BLOCK_LEN * NBLOCKS; + + let core_channels = bsi.acmod.get_num_channels(); + let channels = core_channels + if bsi.lfeon { 1 } else { 0 }; + + let ainfo = NAAudioInfo::new(sinfo.samplerate >> bsi.shift, channels as u8, + SND_F32P_FORMAT, BLOCK_LEN); + + let mut abuf = alloc_audio_buffer(ainfo, duration, bsi.acmod.get_channel_map(bsi.lfeon))?; + let mut adata = abuf.get_abuf_f32().unwrap(); + let mut output = adata.get_data_mut(); + + self.ablk = AudioBlock::new(); + for blk in 0..NBLOCKS { + let all_zero = self.ablk.read(&mut br, &bsi, sinfo.fscod as usize, blk)?; + let off = blk * BLOCK_LEN; + self.ablk.couple_channels(bsi.acmod); + for ch in 0..core_channels { + let dpos = abuf.get_offset(ch) + off; + let dst = &mut output[dpos..][..BLOCK_LEN]; + if !all_zero { + self.ablk.synth_audio_block(&mut self.imdct512, &mut self.imdct256, &mut self.tmp, ch, &mut self.delay[ch], dst); + } else { + self.delay[ch] = [0.0; BLOCK_LEN]; + for i in 0..BLOCK_LEN { dst[i] = 0.0; } + } + } + if bsi.lfeon { + let dpos = abuf.get_offset(core_channels) + off; + let dst = &mut output[dpos..][..BLOCK_LEN]; + if !all_zero { + self.ablk.synth_audio_block(&mut self.imdct512, &mut self.imdct256, &mut self.tmp, LFE_CHANNEL, &mut self.delay[LFE_CHANNEL], dst); + } else { + self.delay[LFE_CHANNEL] = [0.0; BLOCK_LEN]; + for i in 0..BLOCK_LEN { dst[i] = 0.0; } + } + } + } +//todo skip auxdata +//todo do errorcheck + + let mut frm = NAFrame::new_from_pkt(pkt, self.info.replace_info(NACodecTypeInfo::Audio(ainfo)), abuf); + frm.set_keyframe(true); + Ok(Rc::new(RefCell::new(frm))) + } +} + +pub fn get_decoder() -> Box { + Box::new(AudioDecoder::new()) +} + +#[cfg(test)] +mod test { + use test::dec_video::*; + #[test] + fn test_ts102366() { + let file = "assets/RV/sp_sample1.rm"; + test_decode_audio("realmedia", file, Some(12000), "ac3"); + } +} + +const TS102366_SLOW_DECAY: [u8; 4] = [ 0x0F, 0x11, 0x13, 0x15 ]; +const TS102366_FAST_DECAY: [u8; 4] = [ 0x3F, 0x53, 0x67, 0x7B ]; +const TS102366_SLOW_GAIN: [u16; 4] = [ 0x540, 0x4D8, 0x478, 0x410 ]; +const TS102366_FAST_GAIN: [u16; 8] = [ 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380, 0x400 ]; +const TS102366_DBP_TAB: [u16; 4] = [ 0x000, 0x700, 0x900, 0xB00 ]; +const TS102366_FLOOR_TAB: [u16; 8] = [ 0x02F0, 0x02B0, 0x0270, 0x0230, 0x01F0, 0x0170, 0x00F0, 0xF800 ]; + +const TS102366_BIN_TO_BAND: [u8; 256] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 28, + 28, 29, 29, 29, 30, 30, 30, 31, 31, 31, + 32, 32, 32, 33, 33, 33, 34, 34, 34, 35, + 35, 35, 35, 35, 35, 36, 36, 36, 36, 36, + 36, 37, 37, 37, 37, 37, 37, 38, 38, 38, + 38, 38, 38, 39, 39, 39, 39, 39, 39, 40, + 40, 40, 40, 40, 40, 41, 41, 41, 41, 41, + 41, 41, 41, 41, 41, 41, 41, 42, 42, 42, + 42, 42, 42, 42, 42, 42, 42, 42, 42, 43, + 43, 43, 43, 43, 43, 43, 43, 43, 43, 43, + 43, 44, 44, 44, 44, 44, 44, 44, 44, 44, + 44, 44, 44, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, + 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 46, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 47, 47, 47, 47, 47, + 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 49, 49, 49, 49, 49, 49, 49, + 49, 49, 49, 0, 0, 0 +]; +const TS102366_BAND_SIZE: [u8; MAX_BANDS] = [ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, + 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 +]; +const TS102366_BAND_START: [u8; MAX_BANDS] = [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 31, + 34, 37, 40, 43, 46, 49, 55, 61, 67, 73, + 79, 85, 97, 109, 121, 133, 157, 181, 205, 229 +]; + +const TS102366_LATAB: [u16; 256] = [ + 0x0040, 0x003f, 0x003e, 0x003d, 0x003c, 0x003b, 0x003a, 0x0039, + 0x0038, 0x0037, 0x0036, 0x0035, 0x0034, 0x0034, 0x0033, 0x0032, + 0x0031, 0x0030, 0x002f, 0x002f, 0x002e, 0x002d, 0x002c, 0x002c, + 0x002b, 0x002a, 0x0029, 0x0029, 0x0028, 0x0027, 0x0026, 0x0026, + 0x0025, 0x0024, 0x0024, 0x0023, 0x0023, 0x0022, 0x0021, 0x0021, + 0x0020, 0x0020, 0x001f, 0x001e, 0x001e, 0x001d, 0x001d, 0x001c, + 0x001c, 0x001b, 0x001b, 0x001a, 0x001a, 0x0019, 0x0019, 0x0018, + 0x0018, 0x0017, 0x0017, 0x0016, 0x0016, 0x0015, 0x0015, 0x0015, + 0x0014, 0x0014, 0x0013, 0x0013, 0x0013, 0x0012, 0x0012, 0x0012, + 0x0011, 0x0011, 0x0011, 0x0010, 0x0010, 0x0010, 0x000f, 0x000f, + 0x000f, 0x000e, 0x000e, 0x000e, 0x000d, 0x000d, 0x000d, 0x000d, + 0x000c, 0x000c, 0x000c, 0x000c, 0x000b, 0x000b, 0x000b, 0x000b, + 0x000a, 0x000a, 0x000a, 0x000a, 0x000a, 0x0009, 0x0009, 0x0009, + 0x0009, 0x0009, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0007, 0x0006, 0x0006, + 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0006, 0x0005, 0x0005, + 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0005, 0x0004, 0x0004, + 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, 0x0004, + 0x0004, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, + 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0003, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0002, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, + 0x0001, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 +]; +const TS102366_HTH: [[u16; MAX_BANDS]; 3] = [ + [ + 0x04D0, 0x04D0, 0x0440, 0x0400, 0x03E0, 0x03C0, 0x03B0, 0x03B0, 0x03A0, 0x03A0, + 0x03A0, 0x03A0, 0x03A0, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0370, 0x0370, + 0x0360, 0x0360, 0x0350, 0x0350, 0x0340, 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, + 0x02F0, 0x02F0, 0x02F0, 0x02F0, 0x0300, 0x0310, 0x0340, 0x0390, 0x03E0, 0x0420, + 0x0460, 0x0490, 0x04A0, 0x0460, 0x0440, 0x0440, 0x0520, 0x0800, 0x0840, 0x0840, + ], [ + 0x04F0, 0x04F0, 0x0460, 0x0410, 0x03E0, 0x03D0, 0x03C0, 0x03B0, 0x03B0, 0x03A0, + 0x03A0, 0x03A0, 0x03A0, 0x03A0, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0380, + 0x0370, 0x0370, 0x0360, 0x0360, 0x0350, 0x0350, 0x0340, 0x0340, 0x0320, 0x0310, + 0x0300, 0x02F0, 0x02F0, 0x02F0, 0x02F0, 0x0300, 0x0320, 0x0350, 0x0390, 0x03E0, + 0x0420, 0x0450, 0x04A0, 0x0490, 0x0460, 0x0440, 0x0480, 0x0630, 0x0840, 0x0840, + ], [ + 0x0580, 0x0580, 0x04B0, 0x0450, 0x0420, 0x03F0, 0x03E0, 0x03D0, 0x03C0, 0x03B0, + 0x03B0, 0x03B0, 0x03A0, 0x03A0, 0x03A0, 0x03A0, 0x03A0, 0x03A0, 0x03A0, 0x03A0, + 0x0390, 0x0390, 0x0390, 0x0390, 0x0380, 0x0380, 0x0380, 0x0370, 0x0360, 0x0350, + 0x0340, 0x0330, 0x0320, 0x0310, 0x0300, 0x02F0, 0x02F0, 0x02F0, 0x0300, 0x0310, + 0x0330, 0x0350, 0x03C0, 0x0410, 0x0470, 0x04A0, 0x0460, 0x0440, 0x0450, 0x04E0, + ] +]; +const TS102366_BAPTAB: [u8; 64] = [ + 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, + 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15 +]; + +const TS102366_QUANT3_MAP: [[i32; 3]; 27] = [ + [ -0x0AAAAAA, -0x0AAAAAA, -0x0AAAAAA ], + [ -0x0AAAAAA, -0x0AAAAAA, 0x00000000 ], + [ -0x0AAAAAA, -0x0AAAAAA, 0x00AAAAAA ], + [ -0x0AAAAAA, 0x00000000, -0x0AAAAAA ], + [ -0x0AAAAAA, 0x00000000, 0x00000000 ], + [ -0x0AAAAAA, 0x00000000, 0x00AAAAAA ], + [ -0x0AAAAAA, 0x00AAAAAA, -0x0AAAAAA ], + [ -0x0AAAAAA, 0x00AAAAAA, 0x00000000 ], + [ -0x0AAAAAA, 0x00AAAAAA, 0x00AAAAAA ], + [ 0x00000000, -0x0AAAAAA, -0x0AAAAAA ], + [ 0x00000000, -0x0AAAAAA, 0x00000000 ], + [ 0x00000000, -0x0AAAAAA, 0x00AAAAAA ], + [ 0x00000000, 0x00000000, -0x0AAAAAA ], + [ 0x00000000, 0x00000000, 0x00000000 ], + [ 0x00000000, 0x00000000, 0x00AAAAAA ], + [ 0x00000000, 0x00AAAAAA, -0x0AAAAAA ], + [ 0x00000000, 0x00AAAAAA, 0x00000000 ], + [ 0x00000000, 0x00AAAAAA, 0x00AAAAAA ], + [ 0x00AAAAAA, -0x0AAAAAA, -0x0AAAAAA ], + [ 0x00AAAAAA, -0x0AAAAAA, 0x00000000 ], + [ 0x00AAAAAA, -0x0AAAAAA, 0x00AAAAAA ], + [ 0x00AAAAAA, 0x00000000, -0x0AAAAAA ], + [ 0x00AAAAAA, 0x00000000, 0x00000000 ], + [ 0x00AAAAAA, 0x00000000, 0x00AAAAAA ], + [ 0x00AAAAAA, 0x00AAAAAA, -0x0AAAAAA ], + [ 0x00AAAAAA, 0x00AAAAAA, 0x00000000 ], + [ 0x00AAAAAA, 0x00AAAAAA, 0x00AAAAAA ] +]; +const TS102366_QUANT5_MAP: [[i32; 3]; 125] = [ + [ -0x0CCCCCC, -0x0CCCCCC, -0x0CCCCCC ], [ -0x0CCCCCC, -0x0CCCCCC, -0x0666666 ], [ -0x0CCCCCC, -0x0CCCCCC, 0x00000000 ], + [ -0x0CCCCCC, -0x0CCCCCC, 0x00666666 ], [ -0x0CCCCCC, -0x0CCCCCC, 0x00CCCCCC ], + [ -0x0CCCCCC, -0x0666666, -0x0CCCCCC ], [ -0x0CCCCCC, -0x0666666, -0x0666666 ], [ -0x0CCCCCC, -0x0666666, 0x00000000 ], + [ -0x0CCCCCC, -0x0666666, 0x00666666 ], [ -0x0CCCCCC, -0x0666666, 0x00CCCCCC ], + [ -0x0CCCCCC, 0x00000000, -0x0CCCCCC ], [ -0x0CCCCCC, 0x00000000, -0x0666666 ], [ -0x0CCCCCC, 0x00000000, 0x00000000 ], + [ -0x0CCCCCC, 0x00000000, 0x00666666 ], [ -0x0CCCCCC, 0x00000000, 0x00CCCCCC ], + [ -0x0CCCCCC, 0x00666666, -0x0CCCCCC ], [ -0x0CCCCCC, 0x00666666, -0x0666666 ], [ -0x0CCCCCC, 0x00666666, 0x00000000 ], + [ -0x0CCCCCC, 0x00666666, 0x00666666 ], [ -0x0CCCCCC, 0x00666666, 0x00CCCCCC ], + [ -0x0CCCCCC, 0x00CCCCCC, -0x0CCCCCC ], [ -0x0CCCCCC, 0x00CCCCCC, -0x0666666 ], [ -0x0CCCCCC, 0x00CCCCCC, 0x00000000 ], + [ -0x0CCCCCC, 0x00CCCCCC, 0x00666666 ], [ -0x0CCCCCC, 0x00CCCCCC, 0x00CCCCCC ], + [ -0x0666666, -0x0CCCCCC, -0x0CCCCCC ], [ -0x0666666, -0x0CCCCCC, -0x0666666 ], [ -0x0666666, -0x0CCCCCC, 0x00000000 ], + [ -0x0666666, -0x0CCCCCC, 0x00666666 ], [ -0x0666666, -0x0CCCCCC, 0x00CCCCCC ], + [ -0x0666666, -0x0666666, -0x0CCCCCC ], [ -0x0666666, -0x0666666, -0x0666666 ], [ -0x0666666, -0x0666666, 0x00000000 ], + [ -0x0666666, -0x0666666, 0x00666666 ], [ -0x0666666, -0x0666666, 0x00CCCCCC ], + [ -0x0666666, 0x00000000, -0x0CCCCCC ], [ -0x0666666, 0x00000000, -0x0666666 ], [ -0x0666666, 0x00000000, 0x00000000 ], + [ -0x0666666, 0x00000000, 0x00666666 ], [ -0x0666666, 0x00000000, 0x00CCCCCC ], + [ -0x0666666, 0x00666666, -0x0CCCCCC ], [ -0x0666666, 0x00666666, -0x0666666 ], [ -0x0666666, 0x00666666, 0x00000000 ], + [ -0x0666666, 0x00666666, 0x00666666 ], [ -0x0666666, 0x00666666, 0x00CCCCCC ], + [ -0x0666666, 0x00CCCCCC, -0x0CCCCCC ], [ -0x0666666, 0x00CCCCCC, -0x0666666 ], [ -0x0666666, 0x00CCCCCC, 0x00000000 ], + [ -0x0666666, 0x00CCCCCC, 0x00666666 ], [ -0x0666666, 0x00CCCCCC, 0x00CCCCCC ], + [ 0x00000000, -0x0CCCCCC, -0x0CCCCCC ], [ 0x00000000, -0x0CCCCCC, -0x0666666 ], [ 0x00000000, -0x0CCCCCC, 0x00000000 ], + [ 0x00000000, -0x0CCCCCC, 0x00666666 ], [ 0x00000000, -0x0CCCCCC, 0x00CCCCCC ], + [ 0x00000000, -0x0666666, -0x0CCCCCC ], [ 0x00000000, -0x0666666, -0x0666666 ], [ 0x00000000, -0x0666666, 0x00000000 ], + [ 0x00000000, -0x0666666, 0x00666666 ], [ 0x00000000, -0x0666666, 0x00CCCCCC ], + [ 0x00000000, 0x00000000, -0x0CCCCCC ], [ 0x00000000, 0x00000000, -0x0666666 ], [ 0x00000000, 0x00000000, 0x00000000 ], + [ 0x00000000, 0x00000000, 0x00666666 ], [ 0x00000000, 0x00000000, 0x00CCCCCC ], + [ 0x00000000, 0x00666666, -0x0CCCCCC ], [ 0x00000000, 0x00666666, -0x0666666 ], [ 0x00000000, 0x00666666, 0x00000000 ], + [ 0x00000000, 0x00666666, 0x00666666 ], [ 0x00000000, 0x00666666, 0x00CCCCCC ], + [ 0x00000000, 0x00CCCCCC, -0x0CCCCCC ], [ 0x00000000, 0x00CCCCCC, -0x0666666 ], [ 0x00000000, 0x00CCCCCC, 0x00000000 ], + [ 0x00000000, 0x00CCCCCC, 0x00666666 ], [ 0x00000000, 0x00CCCCCC, 0x00CCCCCC ], + [ 0x00666666, -0x0CCCCCC, -0x0CCCCCC ], [ 0x00666666, -0x0CCCCCC, -0x0666666 ], [ 0x00666666, -0x0CCCCCC, 0x00000000 ], + [ 0x00666666, -0x0CCCCCC, 0x00666666 ], [ 0x00666666, -0x0CCCCCC, 0x00CCCCCC ], + [ 0x00666666, -0x0666666, -0x0CCCCCC ], [ 0x00666666, -0x0666666, -0x0666666 ], [ 0x00666666, -0x0666666, 0x00000000 ], + [ 0x00666666, -0x0666666, 0x00666666 ], [ 0x00666666, -0x0666666, 0x00CCCCCC ], + [ 0x00666666, 0x00000000, -0x0CCCCCC ], [ 0x00666666, 0x00000000, -0x0666666 ], [ 0x00666666, 0x00000000, 0x00000000 ], + [ 0x00666666, 0x00000000, 0x00666666 ], [ 0x00666666, 0x00000000, 0x00CCCCCC ], + [ 0x00666666, 0x00666666, -0x0CCCCCC ], [ 0x00666666, 0x00666666, -0x0666666 ], [ 0x00666666, 0x00666666, 0x00000000 ], + [ 0x00666666, 0x00666666, 0x00666666 ], [ 0x00666666, 0x00666666, 0x00CCCCCC ], + [ 0x00666666, 0x00CCCCCC, -0x0CCCCCC ], [ 0x00666666, 0x00CCCCCC, -0x0666666 ], [ 0x00666666, 0x00CCCCCC, 0x00000000 ], + [ 0x00666666, 0x00CCCCCC, 0x00666666 ], [ 0x00666666, 0x00CCCCCC, 0x00CCCCCC ], + [ 0x00CCCCCC, -0x0CCCCCC, -0x0CCCCCC ], [ 0x00CCCCCC, -0x0CCCCCC, -0x0666666 ], [ 0x00CCCCCC, -0x0CCCCCC, 0x00000000 ], + [ 0x00CCCCCC, -0x0CCCCCC, 0x00666666 ], [ 0x00CCCCCC, -0x0CCCCCC, 0x00CCCCCC ], + [ 0x00CCCCCC, -0x0666666, -0x0CCCCCC ], [ 0x00CCCCCC, -0x0666666, -0x0666666 ], [ 0x00CCCCCC, -0x0666666, 0x00000000 ], + [ 0x00CCCCCC, -0x0666666, 0x00666666 ], [ 0x00CCCCCC, -0x0666666, 0x00CCCCCC ], + [ 0x00CCCCCC, 0x00000000, -0x0CCCCCC ], [ 0x00CCCCCC, 0x00000000, -0x0666666 ], [ 0x00CCCCCC, 0x00000000, 0x00000000 ], + [ 0x00CCCCCC, 0x00000000, 0x00666666 ], [ 0x00CCCCCC, 0x00000000, 0x00CCCCCC ], + [ 0x00CCCCCC, 0x00666666, -0x0CCCCCC ], [ 0x00CCCCCC, 0x00666666, -0x0666666 ], [ 0x00CCCCCC, 0x00666666, 0x00000000 ], + [ 0x00CCCCCC, 0x00666666, 0x00666666 ], [ 0x00CCCCCC, 0x00666666, 0x00CCCCCC ], + [ 0x00CCCCCC, 0x00CCCCCC, -0x0CCCCCC ], [ 0x00CCCCCC, 0x00CCCCCC, -0x0666666 ], [ 0x00CCCCCC, 0x00CCCCCC, 0x00000000 ], + [ 0x00CCCCCC, 0x00CCCCCC, 0x00666666 ], [ 0x00CCCCCC, 0x00CCCCCC, 0x00CCCCCC ], +]; +const TS102366_QUANT7_MAP: [i32; 7] = [ + -0xDB6DB6, -0x924924, -0x492492, 0x000000, 0x492492, 0x924924, 0xDB6DB6 +]; +const TS102366_QUANT11_MAP: [[i32; 2]; 121] = [ + [ -0x0E8BA2E, -0x0E8BA2E ], [ -0x0E8BA2E, -0x0BA2E8B ], [ -0x0E8BA2E, -0x08BA2E8 ], + [ -0x0E8BA2E, -0x05D1745 ], [ -0x0E8BA2E, -0x02E8BA2 ], [ -0x0E8BA2E, 0x00000000 ], + [ -0x0E8BA2E, 0x002E8BA2 ], [ -0x0E8BA2E, 0x005D1745 ], [ -0x0E8BA2E, 0x008BA2E8 ], + [ -0x0E8BA2E, 0x00BA2E8B ], [ -0x0E8BA2E, 0x00E8BA2E ], [ -0x0BA2E8B, -0x0E8BA2E ], + [ -0x0BA2E8B, -0x0BA2E8B ], [ -0x0BA2E8B, -0x08BA2E8 ], [ -0x0BA2E8B, -0x05D1745 ], + [ -0x0BA2E8B, -0x02E8BA2 ], [ -0x0BA2E8B, 0x00000000 ], [ -0x0BA2E8B, 0x002E8BA2 ], + [ -0x0BA2E8B, 0x005D1745 ], [ -0x0BA2E8B, 0x008BA2E8 ], [ -0x0BA2E8B, 0x00BA2E8B ], + [ -0x0BA2E8B, 0x00E8BA2E ], [ -0x08BA2E8, -0x0E8BA2E ], [ -0x08BA2E8, -0x0BA2E8B ], + [ -0x08BA2E8, -0x08BA2E8 ], [ -0x08BA2E8, -0x05D1745 ], [ -0x08BA2E8, -0x02E8BA2 ], + [ -0x08BA2E8, 0x00000000 ], [ -0x08BA2E8, 0x002E8BA2 ], [ -0x08BA2E8, 0x005D1745 ], + [ -0x08BA2E8, 0x008BA2E8 ], [ -0x08BA2E8, 0x00BA2E8B ], [ -0x08BA2E8, 0x00E8BA2E ], + [ -0x05D1745, -0x0E8BA2E ], [ -0x05D1745, -0x0BA2E8B ], [ -0x05D1745, -0x08BA2E8 ], + [ -0x05D1745, -0x05D1745 ], [ -0x05D1745, -0x02E8BA2 ], [ -0x05D1745, 0x00000000 ], + [ -0x05D1745, 0x002E8BA2 ], [ -0x05D1745, 0x005D1745 ], [ -0x05D1745, 0x008BA2E8 ], + [ -0x05D1745, 0x00BA2E8B ], [ -0x05D1745, 0x00E8BA2E ], [ -0x02E8BA2, -0x0E8BA2E ], + [ -0x02E8BA2, -0x0BA2E8B ], [ -0x02E8BA2, -0x08BA2E8 ], [ -0x02E8BA2, -0x05D1745 ], + [ -0x02E8BA2, -0x02E8BA2 ], [ -0x02E8BA2, 0x00000000 ], [ -0x02E8BA2, 0x002E8BA2 ], + [ -0x02E8BA2, 0x005D1745 ], [ -0x02E8BA2, 0x008BA2E8 ], [ -0x02E8BA2, 0x00BA2E8B ], + [ -0x02E8BA2, 0x00E8BA2E ], [ 0x00000000, -0x0E8BA2E ], [ 0x00000000, -0x0BA2E8B ], + [ 0x00000000, -0x08BA2E8 ], [ 0x00000000, -0x05D1745 ], [ 0x00000000, -0x02E8BA2 ], + [ 0x00000000, 0x00000000 ], [ 0x00000000, 0x002E8BA2 ], [ 0x00000000, 0x005D1745 ], + [ 0x00000000, 0x008BA2E8 ], [ 0x00000000, 0x00BA2E8B ], [ 0x00000000, 0x00E8BA2E ], + [ 0x002E8BA2, -0x0E8BA2E ], [ 0x002E8BA2, -0x0BA2E8B ], [ 0x002E8BA2, -0x08BA2E8 ], + [ 0x002E8BA2, -0x05D1745 ], [ 0x002E8BA2, -0x02E8BA2 ], [ 0x002E8BA2, 0x00000000 ], + [ 0x002E8BA2, 0x002E8BA2 ], [ 0x002E8BA2, 0x005D1745 ], [ 0x002E8BA2, 0x008BA2E8 ], + [ 0x002E8BA2, 0x00BA2E8B ], [ 0x002E8BA2, 0x00E8BA2E ], [ 0x005D1745, -0x0E8BA2E ], + [ 0x005D1745, -0x0BA2E8B ], [ 0x005D1745, -0x08BA2E8 ], [ 0x005D1745, -0x05D1745 ], + [ 0x005D1745, -0x02E8BA2 ], [ 0x005D1745, 0x00000000 ], [ 0x005D1745, 0x002E8BA2 ], + [ 0x005D1745, 0x005D1745 ], [ 0x005D1745, 0x008BA2E8 ], [ 0x005D1745, 0x00BA2E8B ], + [ 0x005D1745, 0x00E8BA2E ], [ 0x008BA2E8, -0x0E8BA2E ], [ 0x008BA2E8, -0x0BA2E8B ], + [ 0x008BA2E8, -0x08BA2E8 ], [ 0x008BA2E8, -0x05D1745 ], [ 0x008BA2E8, -0x02E8BA2 ], + [ 0x008BA2E8, 0x00000000 ], [ 0x008BA2E8, 0x002E8BA2 ], [ 0x008BA2E8, 0x005D1745 ], + [ 0x008BA2E8, 0x008BA2E8 ], [ 0x008BA2E8, 0x00BA2E8B ], [ 0x008BA2E8, 0x00E8BA2E ], + [ 0x00BA2E8B, -0x0E8BA2E ], [ 0x00BA2E8B, -0x0BA2E8B ], [ 0x00BA2E8B, -0x08BA2E8 ], + [ 0x00BA2E8B, -0x05D1745 ], [ 0x00BA2E8B, -0x02E8BA2 ], [ 0x00BA2E8B, 0x00000000 ], + [ 0x00BA2E8B, 0x002E8BA2 ], [ 0x00BA2E8B, 0x005D1745 ], [ 0x00BA2E8B, 0x008BA2E8 ], + [ 0x00BA2E8B, 0x00BA2E8B ], [ 0x00BA2E8B, 0x00E8BA2E ], [ 0x00E8BA2E, -0x0E8BA2E ], + [ 0x00E8BA2E, -0x0BA2E8B ], [ 0x00E8BA2E, -0x08BA2E8 ], [ 0x00E8BA2E, -0x05D1745 ], + [ 0x00E8BA2E, -0x02E8BA2 ], [ 0x00E8BA2E, 0x00000000 ], [ 0x00E8BA2E, 0x002E8BA2 ], + [ 0x00E8BA2E, 0x005D1745 ], [ 0x00E8BA2E, 0x008BA2E8 ], [ 0x00E8BA2E, 0x00BA2E8B ], + [ 0x00E8BA2E, 0x00E8BA2E ], +]; +const TS102366_QUANT15_MAP: [i32; 15] = [ + -0x0EEEEEE, -0x0CCCCCC, -0x0AAAAAA, -0x0888888, -0x0666666, -0x0444444, -0x0222222, 0x00000000, + 0x00222222, 0x00444444, 0x00666666, 0x00888888, 0x00AAAAAA, 0x00CCCCCC, 0x00EEEEEE, +]; +const TS102366_BAP_BITS: [u8; 10] = [ 5, 6, 7, 8, 9, 10, 11, 12, 14, 16 ]; + +const TS102366_WINDOW: [f32; 256] = [ + 0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130, + 0.00157, 0.00187, 0.00220, 0.00256, 0.00297, 0.00341, 0.00390, 0.00443, + 0.00501, 0.00564, 0.00632, 0.00706, 0.00785, 0.00871, 0.00962, 0.01061, + 0.01166, 0.01279, 0.01399, 0.01526, 0.01662, 0.01806, 0.01959, 0.02121, + 0.02292, 0.02472, 0.02662, 0.02863, 0.03073, 0.03294, 0.03527, 0.03770, + 0.04025, 0.04292, 0.04571, 0.04862, 0.05165, 0.05481, 0.05810, 0.06153, + 0.06508, 0.06878, 0.07261, 0.07658, 0.08069, 0.08495, 0.08935, 0.09389, + 0.09859, 0.10343, 0.10842, 0.11356, 0.11885, 0.12429, 0.12988, 0.13563, + 0.14152, 0.14757, 0.15376, 0.16011, 0.16661, 0.17325, 0.18005, 0.18699, + 0.19407, 0.20130, 0.20867, 0.21618, 0.22382, 0.23161, 0.23952, 0.24757, + 0.25574, 0.26404, 0.27246, 0.28100, 0.28965, 0.29841, 0.30729, 0.31626, + 0.32533, 0.33450, 0.34376, 0.35311, 0.36253, 0.37204, 0.38161, 0.39126, + 0.40096, 0.41072, 0.42054, 0.43040, 0.44030, 0.45023, 0.46020, 0.47019, + 0.48020, 0.49022, 0.50025, 0.51028, 0.52031, 0.53033, 0.54033, 0.55031, + 0.56026, 0.57019, 0.58007, 0.58991, 0.59970, 0.60944, 0.61912, 0.62873, + 0.63827, 0.64774, 0.65713, 0.66643, 0.67564, 0.68476, 0.69377, 0.70269, + 0.71150, 0.72019, 0.72877, 0.73723, 0.74557, 0.75378, 0.76186, 0.76981, + 0.77762, 0.78530, 0.79283, 0.80022, 0.80747, 0.81457, 0.82151, 0.82831, + 0.83496, 0.84145, 0.84779, 0.85398, 0.86001, 0.86588, 0.87160, 0.87716, + 0.88257, 0.88782, 0.89291, 0.89785, 0.90264, 0.90728, 0.91176, 0.91610, + 0.92028, 0.92432, 0.92822, 0.93197, 0.93558, 0.93906, 0.94240, 0.94560, + 0.94867, 0.95162, 0.95444, 0.95713, 0.95971, 0.96217, 0.96451, 0.96674, + 0.96887, 0.97089, 0.97281, 0.97463, 0.97635, 0.97799, 0.97953, 0.98099, + 0.98236, 0.98366, 0.98488, 0.98602, 0.98710, 0.98811, 0.98905, 0.98994, + 0.99076, 0.99153, 0.99225, 0.99291, 0.99353, 0.99411, 0.99464, 0.99513, + 0.99558, 0.99600, 0.99639, 0.99674, 0.99706, 0.99736, 0.99763, 0.99788, + 0.99811, 0.99831, 0.99850, 0.99867, 0.99882, 0.99895, 0.99908, 0.99919, + 0.99929, 0.99938, 0.99946, 0.99953, 0.99959, 0.99965, 0.99969, 0.99974, + 0.99978, 0.99981, 0.99984, 0.99986, 0.99988, 0.99990, 0.99992, 0.99993, + 0.99994, 0.99995, 0.99996, 0.99997, 0.99998, 0.99998, 0.99998, 0.99999, + 0.99999, 0.99999, 0.99999, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, + 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, 1.00000, +]; diff --git a/src/register.rs b/src/register.rs index 7a351c0..b06b597 100644 --- a/src/register.rs +++ b/src/register.rs @@ -138,7 +138,7 @@ static CODEC_REGISTER: &'static [CodecDescription] = &[ desc!(audio; "cook", "RealAudio Cooker"), desc!(audio; "ralf", "RealAudio Lossless"), desc!(audio; "aac", "AAC"), - desc!(audio; "ac3", "AC-3"), + desc!(audio; "ac3", "ETSI TS 102 366"), desc!(audio; "atrac3", "Sony Atrac3"), desc!(audio; "sipro", "Sipro Labs ADPCM"), ]; -- 2.30.2