]> git.nihav.org Git - nihav.git/commitdiff
add nihav-llaudio crate with FLAC, Monkey's Audio, TTA and WavPack support
authorKostya Shishkov <kostya.shishkov@gmail.com>
Mon, 31 Aug 2020 14:08:57 +0000 (16:08 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 5 Sep 2020 17:30:13 +0000 (19:30 +0200)
18 files changed:
nihav-allstuff/Cargo.toml
nihav-allstuff/src/lib.rs
nihav-llaudio/Cargo.toml [new file with mode: 0644]
nihav-llaudio/src/codecs/ape.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/apepred.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/apereader.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/flac.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/mod.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/tta.rs [new file with mode: 0644]
nihav-llaudio/src/codecs/wavpack.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/ape.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/flac.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/mod.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/tta.rs [new file with mode: 0644]
nihav-llaudio/src/demuxers/wavpack.rs [new file with mode: 0644]
nihav-llaudio/src/lib.rs [new file with mode: 0644]
nihav-registry/src/detect.rs
nihav-registry/src/register.rs

index 6c5de36f500c0d2e355d41ba0c6dc7e45af412c4..fc78a051fc3ee1edff7d028fd2d3f4f035591391 100644 (file)
@@ -10,6 +10,7 @@ nihav_commonfmt = { path = "../nihav-commonfmt" }
 nihav_duck = { path = "../nihav-duck" }
 nihav_game = { path = "../nihav-game" }
 nihav_indeo = { path = "../nihav-indeo" }
+nihav_llaudio = { path = "../nihav-llaudio" }
 nihav_ms = { path = "../nihav-ms" }
 nihav_qt = { path = "../nihav-qt" }
 nihav_rad = { path = "../nihav-rad" }
index 5ef4fe9d55e09f22c9bcb507ea17cd1bd3324206..90a7766bf323109a39f42f20902788db7e6f4978 100644 (file)
@@ -4,6 +4,7 @@ extern crate nihav_commonfmt;
 extern crate nihav_duck;
 extern crate nihav_game;
 extern crate nihav_indeo;
+extern crate nihav_llaudio;
 extern crate nihav_ms;
 extern crate nihav_rad;
 extern crate nihav_realmedia;
@@ -25,6 +26,9 @@ use nihav_game::game_register_all_demuxers;
 
 use nihav_indeo::indeo_register_all_decoders;
 
+use nihav_llaudio::llaudio_register_all_decoders;
+use nihav_llaudio::llaudio_register_all_demuxers;
+
 use nihav_ms::ms_register_all_decoders;
 use nihav_ms::ms_register_all_encoders;
 
@@ -42,6 +46,7 @@ pub fn nihav_register_all_decoders(rd: &mut RegisteredDecoders) {
     duck_register_all_decoders(rd);
     game_register_all_decoders(rd);
     indeo_register_all_decoders(rd);
+    llaudio_register_all_decoders(rd);
     ms_register_all_decoders(rd);
     qt_register_all_decoders(rd);
     rad_register_all_decoders(rd);
@@ -52,6 +57,7 @@ pub fn nihav_register_all_decoders(rd: &mut RegisteredDecoders) {
 pub fn nihav_register_all_demuxers(rd: &mut RegisteredDemuxers) {
     generic_register_all_demuxers(rd);
     game_register_all_demuxers(rd);
+    llaudio_register_all_demuxers(rd);
     rad_register_all_demuxers(rd);
     realmedia_register_all_demuxers(rd);
 }
diff --git a/nihav-llaudio/Cargo.toml b/nihav-llaudio/Cargo.toml
new file mode 100644 (file)
index 0000000..229c018
--- /dev/null
@@ -0,0 +1,29 @@
+[package]
+name = "nihav_llaudio"
+version = "0.1.0"
+authors = ["Kostya Shishkov <kostya.shishkov@gmail.com>"]
+edition = "2018"
+
+[dependencies.nihav_core]
+path = "../nihav-core"
+features = []
+
+[dependencies.nihav_codec_support]
+path = "../nihav-codec-support"
+
+[features]
+default = ["all_decoders", "all_demuxers"]
+
+all_decoders = ["decoder_ape", "decoder_flac", "decoder_tta", "decoder_wavpack"]
+decoders = []
+decoder_ape = ["decoders"]
+decoder_flac = ["decoders"]
+decoder_tta = ["decoders"]
+decoder_wavpack = ["decoders"]
+
+all_demuxers = ["demuxer_ape", "demuxer_flac", "demuxer_tta", "demuxer_wavpack"]
+demuxers = []
+demuxer_ape = ["demuxers"]
+demuxer_flac = ["demuxers"]
+demuxer_tta = ["demuxers"]
+demuxer_wavpack = ["demuxers"]
diff --git a/nihav-llaudio/src/codecs/ape.rs b/nihav-llaudio/src/codecs/ape.rs
new file mode 100644 (file)
index 0000000..a89f0c5
--- /dev/null
@@ -0,0 +1,363 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+
+use super::apepred::*;
+use super::apereader::*;
+
+struct APEDecoder {
+    ainfo:          NAAudioInfo,
+    chmap:          NAChannelMap,
+    version:        u16,
+    decode_mono:    fn(&mut Coder, &mut [i32]) -> DecoderResult<()>,
+    decode_stereo:  fn(&mut Coder, &mut [i32], &mut [i32]) -> DecoderResult<()>,
+    is_stereo:      bool,
+    left:           Vec<i32>,
+    right:          Vec<i32>,
+    fmode:          FilterMode,
+    data:           Vec<u8>,
+    blocksperframe: usize,
+}
+
+impl APEDecoder {
+    fn new() -> Self {
+        Self {
+            ainfo:          NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+            chmap:          NAChannelMap::new(),
+            version:        0,
+            decode_mono:    decode_mono_dummy,
+            decode_stereo:  decode_stereo_dummy,
+            is_stereo:      false,
+            left:           Vec::new(),
+            right:          Vec::new(),
+            fmode:          FilterMode::None,
+            data:           Vec::new(),
+            blocksperframe: 0,
+        }
+    }
+}
+
+impl NADecoder for APEDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+            if let Some(buf) = info.get_extradata() {
+                let mut mr = MemoryReader::new_read(&buf);
+                let mut br = ByteReader::new(&mut mr);
+                let version             = br.read_u16le()?;
+                let compression         = br.read_u16le()?;
+                let _flags              = br.read_u16le()?;
+                let channels            = br.read_byte()?;
+                let bits                = br.read_byte()?;
+                let srate               = br.read_u32le()?;
+                let blocksperframe      = br.read_u32le()? as usize;
+
+                validate!(channels > 0);
+                validate!(bits > 0 && bits <= 32);
+                validate!((compression % 1000) == 0 && compression > 0 && compression <= 5000);
+                validate!(compression < 5000 || version >= 3930);
+                if bits != 16 {
+                    return Err(DecoderError::NotImplemented);
+                }
+                if version > 3990 {
+                    return Err(DecoderError::NotImplemented);
+                }
+
+                self.version = version;
+                self.blocksperframe = blocksperframe;
+                self.is_stereo = channels == 2;
+                self.left.resize(blocksperframe, 0);
+                if self.is_stereo {
+                    self.right.resize(blocksperframe, 0);
+                }
+
+                self.decode_mono = if version >= 3990 {
+                        decode_mono_3990
+                    } else if version >= 3910 {
+                        decode_mono_3910
+                    } else if version >= 3900 {
+                        decode_mono_3900
+                    } else if version >= 3890 {
+                        decode_mono_3890
+                    } else if version >= 3860 {
+                        decode_mono_3860
+                    } else {
+                        decode_mono_0000
+                    };
+                self.decode_stereo = if version >= 3990 {
+                        decode_stereo_3990
+                    } else if version >= 3930 {
+                        decode_stereo_3930
+                    } else if version >= 3910 {
+                        decode_stereo_3910
+                    } else if version >= 3900 {
+                        decode_stereo_3900
+                    } else if version >= 3890 {
+                        decode_stereo_3890
+                    } else if version >= 3860 {
+                        decode_stereo_3860
+                    } else {
+                        decode_stereo_0000
+                    };
+                self.fmode = FilterMode::new(version, compression);
+
+                self.chmap = if channels == 1 {
+                        NAChannelMap::from_str("C").unwrap()
+                    } else if channels == 2 {
+                        NAChannelMap::from_str("L,R").unwrap()
+                    } else {
+                        return Err(DecoderError::NotImplemented);
+                    };
+                self.ainfo = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 4602);
+                Ok(())
+            } else {
+                Err(DecoderError::InvalidData)
+            }
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() > 9);
+
+            let nblocks                 = read_u32le(&pktbuf[0..])? as usize;
+            validate!(nblocks > 0);
+            let bits                    = u32::from(pktbuf[4]);
+            validate!(bits < 32);
+            self.data.truncate(0);
+            self.data.reserve((pktbuf.len() & !3) + 2);
+            for word in pktbuf[8..].chunks_exact(4) {
+                self.data.push(word[3]);
+                self.data.push(word[2]);
+                self.data.push(word[1]);
+                self.data.push(word[0]);
+            }
+            if self.version < 3950 {
+                self.data.push(0);
+                self.data.push(0);
+            }
+
+            let (mut coder, ref_crc, fflags) = if self.version < 3900 {
+                    let mut br = BitReader::new(&self.data, BitReaderMode::BE);
+                                          br.skip(bits)?;
+                    let mut crc         = br.read(32)?;
+                    let fflags = if self.version >= 3830 && (crc & 0x80000000) != 0 {
+                            crc ^= 0x80000000;
+                                          br.read(32)?
+                        } else {
+                            0
+                        };
+                    (Coder::Rice(RiceCoder::new(br)), crc, fflags)
+                } else {
+                    let mut boff = (bits / 8) as usize;
+                    let mut crc         = read_u32be(&self.data[boff..])?;
+                    boff += 4;
+                    let fflags = if (crc & 0x80000000) != 0 {
+                            crc ^= 0x80000000;
+                            let flg     = read_u32be(&self.data[boff..])?;
+                            boff += 4;
+                            flg
+                        } else {
+                            0
+                        };
+                    // it ignores first byte anyway
+                    (Coder::Range(RangeCoder::new(&self.data[boff + 1..])), crc, fflags)
+                };
+            self.left.resize(nblocks, 0);
+            if self.is_stereo {
+                self.right.resize(nblocks, 0);
+            }
+            if (fflags & 3) == 0 {
+                if !self.is_stereo || (fflags & 4) != 0 {
+                    (self.decode_mono)(&mut coder, &mut self.left)?;
+                    self.fmode.filter_mono(&mut self.left);
+
+                    if (fflags & 4) != 0 {
+                        self.right.copy_from_slice(&self.left);
+                    }
+                } else {
+                    (self.decode_stereo)(&mut coder, &mut self.left, &mut self.right)?;
+                    self.fmode.filter_stereo(&mut self.left, &mut self.right);
+                }
+            }
+
+            if self.version >= 0x3990 || nblocks == self.blocksperframe {
+                let mut crc = 0xFFFFFFFF;
+                if !self.is_stereo {
+                    for el in self.left.iter() {
+                        let byte1 = *el as u8;
+                        let byte0 = (*el >> 8) as u8;
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+                    }
+                } else {
+                    for (l, r) in self.left.iter().zip(self.right.iter()) {
+                        let byte1 = *l as u8;
+                        let byte0 = (*l >> 8) as u8;
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+                        let byte1 = *r as u8;
+                        let byte0 = (*r >> 8) as u8;
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte1) as usize];
+                        crc = (crc >> 8) ^ CRC32_TAB[((crc as u8) ^ byte0) as usize];
+                    }
+                }
+                crc = !crc;
+                if self.version >= 3830 {
+                    crc >>= 1;
+                }
+                if crc != ref_crc {
+                    return Err(DecoderError::ChecksumError);
+                }
+            }
+
+            let abuf = alloc_audio_buffer(self.ainfo, nblocks, self.chmap.clone())?;
+            let mut adata = abuf.get_abuf_i16().unwrap();
+            let off1 = adata.get_offset(1);
+            let dst = adata.get_data_mut().unwrap();
+            let (left, right) = dst.split_at_mut(off1);
+            for (dst, src) in left.iter_mut().zip(self.left.iter()) {
+                *dst = *src as i16;
+            }
+            if self.is_stereo {
+                for (dst, src) in right.iter_mut().zip(self.right.iter()) {
+                    *dst = *src as i16;
+                }
+            }
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+            frm.set_duration(Some(nblocks as u64));
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for APEDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(APEDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::llaudio_register_all_decoders;
+    use crate::llaudio_register_all_demuxers;
+    #[test]
+    fn test_ape_3990() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight.ape", Some(3), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x569e002b, 0xd93772a9, 0x1cfd81cd, 0xad81319a]));
+    }
+    #[test]
+    fn test_ape_3940() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac394b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+    #[test]
+    fn test_ape_3920() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac392b2-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+    #[test]
+    fn test_ape_3910() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac391b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+    #[test]
+    fn test_ape_3890() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac389b1-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+    #[test]
+    fn test_ape_3880() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac388-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+    #[test]
+    fn test_ape_3800() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("ape", "ape", "assets/LLaudio/ape/luckynight-mac380-c4000.ape", Some(1), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xeb55ece6, 0xe5f22759, 0xd0696dd6, 0x84ae9a6c]));
+    }
+}
+
+const CRC32_TAB: [u32; 256] = [
+    0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
+    0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
+    0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
+    0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
+    0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
+    0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
+    0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+    0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
+    0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
+    0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
+    0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
+    0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
+    0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
+    0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+    0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
+    0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
+    0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
+    0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
+    0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
+    0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
+    0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+    0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
+    0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
+    0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
+    0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
+    0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
+    0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
+    0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+    0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
+    0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
+    0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
+    0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
+];
diff --git a/nihav-llaudio/src/codecs/apepred.rs b/nihav-llaudio/src/codecs/apepred.rs
new file mode 100644 (file)
index 0000000..6aad207
--- /dev/null
@@ -0,0 +1,472 @@
+const HISTORY_SIZE: usize = 512;
+
+fn val2sign(val: i32) -> i32 {
+    if val > 0 {
+        -1
+    } else if val < 0 {
+        1
+    } else {
+        0
+    }
+}
+
+pub struct OldFilt {
+    version:        u16,
+    compression:    u16,
+}
+
+pub struct NewFilt {
+    version:        u16,
+    filters:        [NFilterContext; 3],
+    lfilt:          LastFilterContext,
+    rfilt:          LastFilterContext,
+}
+
+#[allow(clippy::large_enum_variant)]
+pub enum FilterMode {
+    Old(OldFilt),
+    New(NewFilt),
+    None,
+}
+
+impl FilterMode {
+    pub fn new(version: u16, compression: u16) -> Self {
+        if version < 3930 {
+            FilterMode::Old(OldFilt::new(version, compression))
+        } else {
+            FilterMode::New(NewFilt::new(version, compression))
+        }
+    }
+    pub fn filter_mono(&mut self, l: &mut [i32]) {
+        match *self {
+            FilterMode::Old(ref mut ofilt) => ofilt.filter(l),
+            FilterMode::New(ref mut nfilt) => nfilt.filter_mono(l),
+            FilterMode::None => unreachable!(),
+        };
+    }
+    pub fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) {
+        match *self {
+            FilterMode::Old(ref mut ofilt) => {
+                ofilt.filter(l);
+                ofilt.filter(r);
+                for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+                    let new_l = *l - *r / 2;
+                    let new_r = *r + new_l;
+                    *l = new_l;
+                    *r = new_r;
+                }
+            },
+            FilterMode::New(ref mut nfilt) => {
+                nfilt.filter_stereo(l, r);
+                for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+                    let new_l = *r - *l / 2;
+                    let new_r = *l + new_l;
+                    *l = new_l;
+                    *r = new_r;
+                }
+            },
+            FilterMode::None => unreachable!(),
+        };
+    }
+}
+
+const NEW_FILTER_PARAMS: [[(u8, u8); 3]; 5] = [
+    [ (0,  0), ( 0,  0), ( 0,  0) ],
+    [ (1, 11), ( 0,  0), ( 0,  0) ],
+    [ (4, 11), ( 0,  0), ( 0,  0) ],
+    [ (2, 10), (16, 13), ( 0,  0) ],
+    [ (1, 11), (16, 13), (80, 15) ],
+];
+
+#[derive(Clone,Default)]
+struct NFilterContext {
+    buf:        Vec<i32>,
+    coeffs:     Vec<i32>,
+    order:      usize,
+    bits:       u8,
+    avg:        i32,
+    new:        bool,
+}
+
+impl NFilterContext {
+    fn new(ord16: u8, bits: u8, new: bool) -> Self {
+        let order = ord16 as usize * 16;
+        Self {
+            buf:        if order > 0 { vec![0; order * 2 + HISTORY_SIZE] } else { Vec::new() },
+            coeffs:     vec![0; order],
+            order,
+            bits,
+            avg:        0,
+            new,
+        }
+    }
+    fn reset(&mut self) {
+        for el in self.buf[..self.order * 2].iter_mut() { *el = 0; }
+        for el in self.coeffs.iter_mut() { *el = 0; }
+        self.avg = 0;
+    }
+    fn apply(&mut self, dst: &mut [i32]) {
+        if self.order == 0 { return; }
+        let mut adapt_pos = self.order;
+        let mut delay_pos = self.order * 2;
+        for el in dst.iter_mut() {
+            let mut sum = 0i32;
+            for (i, coef) in self.coeffs.iter_mut().enumerate() {
+                sum += *coef * self.buf[delay_pos - self.order + i];
+                if *el < 0 {
+                    *coef += self.buf[adapt_pos - self.order + i];
+                } else if *el > 0 {
+                    *coef -= self.buf[adapt_pos - self.order + i];
+                }
+            }
+            let pred = (sum + (1 << (self.bits - 1))) >> self.bits;
+            let val = *el + pred;
+            *el = val;
+            self.buf[delay_pos] = val.min(32767).max(-32768);
+            if self.new {
+                let aval = val.abs();
+                let sign = val2sign(val);
+                self.buf[adapt_pos] = if aval == 0 {
+                        0
+                    } else if aval <= self.avg * 4 / 3 {
+                        sign * 8
+                    } else if aval <= self.avg * 3 {
+                        sign * 16
+                    } else {
+                        sign * 32
+                    };
+                self.avg += (aval - self.avg) / 16;
+                self.buf[adapt_pos - 1] >>= 1;
+                self.buf[adapt_pos - 2] >>= 1;
+                self.buf[adapt_pos - 8] >>= 1;
+            } else {
+                self.buf[adapt_pos] = 4 * val2sign(val);
+                self.buf[adapt_pos - 4] >>= 1;
+                self.buf[adapt_pos - 8] >>= 1;
+            }
+            delay_pos += 1;
+            adapt_pos += 1;
+            if delay_pos == HISTORY_SIZE + self.order * 2 {
+                delay_pos = self.order * 2;
+                adapt_pos = self.order;
+                for i in 0..self.order * 2 {
+                    self.buf[i] = self.buf[HISTORY_SIZE + i];
+                }
+            }
+        }
+    }
+}
+
+#[derive(Clone,Copy,Default)]
+struct LastFilterContext {
+    last_a:     i32,
+    filter_a:   i32,
+    filter_b:   i32,
+    coeffs_a:   [i32; 4],
+    coeffs_b:   [i32; 5],
+    delay_a:    [i32; 4],
+    adapt_a:    [i32; 4],
+    delay_b:    [i32; 5],
+    adapt_b:    [i32; 5],
+}
+
+impl LastFilterContext {
+    fn init(&mut self) {
+        const COEFFS_A_NEW: [i32; 4] = [360, 317, -109, 98];
+
+        self.filter_a = 0;
+        self.filter_b = 0;
+        self.coeffs_a = COEFFS_A_NEW;
+        self.coeffs_b = [0; 5];
+        self.last_a   = 0;
+        self.delay_a  = [0; 4];
+        self.adapt_a  = [0; 4];
+        self.delay_b  = [0; 5];
+        self.adapt_b  = [0; 5];
+    }
+    fn predict_a(&mut self) -> i32 {
+        for i in (0..3).rev() {
+            self.delay_a[i + 1] = self.delay_a[i];
+            self.adapt_a[i + 1] = self.adapt_a[i];
+        }
+        self.delay_a[0] = self.last_a;
+        self.delay_a[1] = self.last_a - self.delay_a[1];
+        self.adapt_a[0] = val2sign(self.delay_a[0]);
+        self.adapt_a[1] = val2sign(self.delay_a[1]);
+
+        self.delay_a[0] * self.coeffs_a[0] +
+        self.delay_a[1] * self.coeffs_a[1] +
+        self.delay_a[2] * self.coeffs_a[2] +
+        self.delay_a[3] * self.coeffs_a[3]
+    }
+    fn predict_b(&mut self, other_a: i32) -> i32 {
+        for i in (0..4).rev() {
+            self.delay_b[i + 1] = self.delay_b[i];
+            self.adapt_b[i + 1] = self.adapt_b[i];
+        }
+        self.delay_b[0] = other_a - ((self.filter_b * 31) >> 5);
+        self.delay_b[1] = self.delay_b[0] - self.delay_b[1];
+        self.adapt_b[0] = val2sign(self.delay_b[0]);
+        self.adapt_b[1] = val2sign(self.delay_b[1]);
+
+        self.filter_b = other_a;
+
+        (self.delay_b[0] * self.coeffs_b[0] +
+         self.delay_b[1] * self.coeffs_b[1] +
+         self.delay_b[2] * self.coeffs_b[2] +
+         self.delay_b[3] * self.coeffs_b[3] +
+         self.delay_b[4] * self.coeffs_b[4]) >> 1
+    }
+    fn update_a(&mut self, pred: i32, diff: i32) -> i32 {
+        self.last_a = diff + (pred >> 10);
+        let sign = val2sign(diff);
+        for i in 0..4 {
+            self.coeffs_a[i] += self.adapt_a[i] * sign;
+        }
+        self.filter_a = self.last_a + ((self.filter_a * 31) >> 5);
+
+        self.filter_a
+    }
+    fn update_b(&mut self, diff: i32) {
+        let sign = val2sign(diff);
+        for i in 0..5 {
+            self.coeffs_b[i] += self.adapt_b[i] * sign;
+        }
+    }
+    fn predict_3930(&mut self, diff: i32) -> i32 {
+        for i in (0..3).rev() {
+            self.delay_a[i + 1] = self.delay_a[i];
+        }
+        self.delay_a[0] = self.last_a;
+        let d0 = self.delay_a[0];
+        let d1 = self.delay_a[0] - self.delay_a[1];
+        let d2 = self.delay_a[1] - self.delay_a[2];
+        let d3 = self.delay_a[2] - self.delay_a[3];
+
+        let pred = (self.coeffs_a[0] * d0 +
+                    self.coeffs_a[1] * d1 +
+                    self.coeffs_a[2] * d2 +
+                    self.coeffs_a[3] * d3) >> 9;
+        self.last_a = diff + pred;
+        self.filter_a = self.last_a + ((self.filter_a * 31) >> 5);
+
+        let sign = val2sign(diff);
+        self.coeffs_a[0] += if d0 < 0 { sign } else { -sign };
+        self.coeffs_a[1] += if d1 < 0 { sign } else { -sign };
+        self.coeffs_a[2] += if d2 < 0 { sign } else { -sign };
+        self.coeffs_a[3] += if d3 < 0 { sign } else { -sign };
+
+        self.filter_a
+    }
+}
+
+impl NewFilt {
+    fn new(version: u16, compression: u16) -> Self {
+        let cidx = (compression / 1000) as usize - 1;
+        let mut obj = Self {
+            version,
+            filters:        [NFilterContext::default(), NFilterContext::default(), NFilterContext::default()],
+            lfilt:          LastFilterContext::default(),
+            rfilt:          LastFilterContext::default(),
+        };
+        obj.version = version;
+        let new = version >= 3980;
+        for i in 0..3 {
+            let (ord16, bits) = NEW_FILTER_PARAMS[cidx][i];
+            obj.filters[i] = NFilterContext::new(ord16, bits, new);
+        }
+        obj
+    }
+    fn filter_mono(&mut self, dst: &mut [i32]) {
+        for filt in self.filters.iter_mut() {
+            filt.reset();
+            filt.apply(dst);
+        }
+        self.lfilt.init();
+        if self.version >= 3950 {
+            for el in dst.iter_mut() {
+                let pred = self.lfilt.predict_a();
+                *el = self.lfilt.update_a(pred, *el);
+            }
+        } else {
+            for el in dst.iter_mut() {
+                *el = self.lfilt.predict_3930(*el);
+            }
+        }
+    }
+    fn filter_stereo(&mut self, l: &mut [i32], r: &mut [i32]) {
+        for filt in self.filters.iter_mut() {
+            filt.reset();
+            filt.apply(l);
+            filt.reset();
+            filt.apply(r);
+        }
+        self.lfilt.init();
+        self.rfilt.init();
+        if self.version >= 3950 {
+            for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+                let mut pred = self.lfilt.predict_a();
+                pred += self.lfilt.predict_b(self.rfilt.filter_a);
+                let new_l = self.lfilt.update_a(pred, *l);
+                self.lfilt.update_b(*l);
+                *l = new_l;
+
+                let mut pred = self.rfilt.predict_a();
+                pred += self.rfilt.predict_b(self.lfilt.filter_a);
+                let new_r = self.rfilt.update_a(pred, *r);
+                self.rfilt.update_b(*r);
+                *r = new_r;
+            }
+        } else {
+            for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+                let new_l = self.lfilt.predict_3930(*r);
+                let new_r = self.rfilt.predict_3930(*l);
+                *l = new_l;
+                *r = new_r;
+            }
+        }
+    }
+}
+
+impl OldFilt {
+    fn new(version: u16, compression: u16) -> Self {
+        Self {
+            version, compression
+        }
+    }
+    fn filter(&mut self, dst: &mut [i32]) {
+        match self.compression {
+            1000 => {
+                Self::filter_fast(dst);
+            },
+            2000 => {
+                Self::filter_normal(dst, 4, 10);
+            },
+            3000 => {
+                Self::filter_high(dst, 16, 9);
+                Self::filter_normal(dst, 16, 10);
+            },
+            4000 => {
+                if self.version < 3830 {
+                    Self::filter_high(dst, 128, 11);
+                    Self::filter_normal(dst, 128, 10);
+                } else {
+                    Self::filter_extra_high(dst);
+                    Self::filter_high(dst, 256, 12);
+                    Self::filter_normal(dst, 256, 11);
+                }
+            },
+            _ => unreachable!(),
+        };
+    }
+    fn filter_fast(dst: &mut [i32]) {
+        const COEFF_A_FAST: i32 = 375;
+
+        if dst.len() <= 3 {
+            return;
+        }
+        let mut delay = [dst[1], dst[0]];
+        let mut last = dst[2];
+        let mut filter = dst[2];
+        let mut weight = COEFF_A_FAST;
+        for el in dst[3..].iter_mut() {
+            delay[1] = delay[0];
+            delay[0] = last;
+            let pred = delay[0] * 2 - delay[1];
+            last = *el + ((pred * weight) >> 9);
+            if (*el ^ pred) > 0 {
+                weight += 1;
+            } else {
+                weight -= 1;
+            }
+            filter += last;
+            *el = filter;
+        }
+    }
+    fn filter_normal(dst: &mut [i32], start: usize, shift: u8) {
+        const COEFFS_A_NORMAL: [i32; 3] = [64, 115, 64];
+        const COEFFS_B_NORMAL: [i32; 2] = [740, 0];
+
+        let mut last = 0;
+        let mut coeffs_a = COEFFS_A_NORMAL;
+        let mut coeffs_b = COEFFS_B_NORMAL;
+        let mut filter_a = 0;
+        let mut filter_b = 0;
+        let mut delay_a = [0; 3];
+        let mut delay_b = [0; 2];
+
+        for (i, el) in dst.iter_mut().enumerate() {
+            delay_a[2] = delay_a[1]; delay_a[1] = delay_a[0]; delay_a[0] = last;
+            delay_b[1] = delay_b[0]; delay_b[0] = filter_b;
+            if i < start {
+                let val = *el + filter_a;
+                last     = *el;
+                filter_b = *el;
+                filter_a = val;
+                *el = val;
+                continue;
+            }
+            let a0 = delay_a[0] + (delay_a[2] - delay_a[1]) * 8;
+            let a1 = (delay_a[0] - delay_a[1]) * 2;
+            let a2 = delay_a[0];
+            let b0 = delay_b[0] * 2 - delay_b[1];
+            let b1 = delay_b[0];
+
+            let pred_a = a0 * coeffs_a[0] + a1 * coeffs_a[1] + a2 * coeffs_a[2];
+            let pred_b = b0 * coeffs_b[0] - b1 * coeffs_b[1];
+
+            let sign = val2sign(*el);
+            coeffs_a[0] += (((a0 >> 30) & 2) - 1) * sign;
+            coeffs_a[1] += (((a1 >> 28) & 8) - 4) * sign;
+            coeffs_a[2] += (((a2 >> 28) & 8) - 4) * sign;
+            last = *el + (pred_a >> 11);
+
+            let sign = val2sign(last);
+            coeffs_b[0] += (((b0 >> 29) & 4) - 2) * sign;
+            coeffs_b[1] -= (((b1 >> 30) & 2) - 1) * sign;
+
+            filter_b = last + (pred_b >> shift);
+            filter_a = filter_b + ((filter_a * 31) >> 5);
+
+            *el = filter_a;
+        }
+    }
+    fn filter_high(dst: &mut [i32], order: usize, shift: u8) {
+        let mut coeffs = [0i32; 256];
+        let mut delay  = [0i32; 256];
+        if dst.len() <= order {
+            return;
+        }
+        delay[..order].copy_from_slice(&dst[..order]);
+        for el in dst[order..].iter_mut() {
+            let sign = val2sign(*el);
+            let mut sum = 0;
+            for i in 0..order {
+                sum += delay[i] * coeffs[i];
+                coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign;
+            }
+            *el -= sum >> shift;
+            for i in 0..order-1 {
+                delay[i] = delay[i + 1];
+            }
+            delay[order - 1] = *el;
+        }
+    }
+    fn filter_extra_high(dst: &mut [i32]) {
+        let mut coeffs = [0i32; 8];
+        let mut delay  = [0i32; 8];
+        for el in dst[256..].iter_mut() {
+            let sign = val2sign(*el);
+            let mut sum = 0;
+            for i in 0..8 {
+                sum += delay[i] * coeffs[i];
+                coeffs[i] -= (((delay[i] >> 30) & 2) - 1) * sign;
+            }
+            for i in (0..7).rev() {
+                delay[i + 1] = delay[i];
+            }
+            delay[0] = *el;
+            *el -= sum >> 9;
+        }
+    }
+}
diff --git a/nihav-llaudio/src/codecs/apereader.rs b/nihav-llaudio/src/codecs/apereader.rs
new file mode 100644 (file)
index 0000000..acd602b
--- /dev/null
@@ -0,0 +1,489 @@
+use nihav_core::codecs::{DecoderError, DecoderResult};
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+pub struct RiceParams {
+    k:      u8,
+    sum:    u32
+}
+
+impl RiceParams {
+    pub fn new() -> Self {
+        let k = 10;
+        Self { k, sum: 1 << (k + 4) }
+    }
+    fn update(&mut self, val: u32) {
+        let limit = if self.k > 0 { 1 << (self.k + 4) } else { 0 };
+        self.sum -= (self.sum + 16) >> 5;
+        self.sum += (val + 1) / 2;
+        if self.sum < limit {
+            self.k -= 1;
+        } else if (self.sum >= (1 << (self.k + 5))) && (self.k < 27) {
+            self.k += 1;
+        }
+    }
+    fn update_old(&mut self, val: u32) {
+        let limit = if self.k > 0 { 1 << (self.k + 4) } else { 0 };
+        self.sum -= (self.sum + 8) >> 4;
+        self.sum += val;
+        if self.sum < limit {
+            self.k -= 1;
+        } else if (self.sum >= (1 << (self.k + 5))) && (self.k < 24) {
+            self.k += 1;
+        }
+    }
+}
+
+pub struct RiceCoder<'a> {
+    br:     BitReader<'a>,
+    rice_x: RiceParams,
+    rice_y: RiceParams,
+}
+
+impl<'a> RiceCoder<'a> {
+    pub fn new(br: BitReader<'a>) -> Self {
+        Self {
+            br,
+            rice_x: RiceParams::new(),
+            rice_y: RiceParams::new(),
+        }
+    }
+}
+
+struct ARangeCoder<'a> {
+    src:    &'a [u8],
+    pos:    usize,
+    low:    u32,
+    range:  u32,
+    help:   u32,
+    buffer: u32,
+    error:  bool,
+}
+
+pub struct RangeCoder<'a> {
+    rc:     ARangeCoder<'a>,
+    rice_x: RiceParams,
+    rice_y: RiceParams,
+}
+
+impl<'a> RangeCoder<'a> {
+    pub fn new(src: &'a [u8]) -> Self {
+        Self {
+            rc:     ARangeCoder::new(src),
+            rice_x: RiceParams::new(),
+            rice_y: RiceParams::new(),
+        }
+    }
+    fn had_errors(&self) -> bool { self.rc.error }
+}
+
+const RANGE_BITS: u8 = 32;
+const TOP: u32       = 1 << (RANGE_BITS - 1);
+const BOTTOM: u32    = TOP >> 8;
+const START_BITS: u8 = ((RANGE_BITS - 2) & 7) + 1;
+
+const MAX_MODEL_VAL: u32 = 63;
+
+impl<'a> ARangeCoder<'a> {
+    fn new(src: &'a [u8]) -> Self {
+        let buffer = u32::from(src[0]);
+        Self {
+            src:    &src[1..],
+            pos:    0,
+            low:    buffer >> (8 - START_BITS),
+            range:  1 << START_BITS,
+            help:   0,
+            buffer,
+            error:  false,
+        }
+    }
+    fn reset(&mut self) {
+        if self.pos == 0 {
+            self.error = true;
+        } else {
+            self.pos -= 1;
+        }
+        if self.pos < self.src.len() - 1 {
+            self.buffer = u32::from(self.src[self.pos]);
+            self.pos += 1;
+        }
+        self.low    = self.buffer >> (8 - START_BITS);
+        self.range  = 1 << START_BITS;
+        self.help   = 0;
+    }
+    fn normalise(&mut self) {
+        while self.range <= BOTTOM {
+            self.buffer <<= 8;
+            if self.pos < self.src.len() {
+                self.buffer |= u32::from(self.src[self.pos]);
+                self.pos += 1;
+            } else {
+                self.error = true;
+            }
+            self.low   <<= 8;
+            self.low    |= (self.buffer >> 1) & 0xFF;
+            self.range <<= 8;
+        }
+    }
+    fn get_freq(&mut self, freq: u32) -> u32 {
+        self.normalise();
+        self.help = self.range / freq;
+        self.low / self.help
+    }
+    fn get_bits(&mut self, bits: u8) -> u32 {
+        self.normalise();
+        self.help = self.range >> bits;
+        self.low / self.help
+    }
+    fn update(&mut self, interval: u32, low: u32) {
+        self.low    -= self.help * low;
+        self.range   = self.help * interval;
+    }
+    fn decode_freq(&mut self, freq: u32) -> u32 {
+        let sym = self.get_freq(freq);
+        self.update(1, sym);
+        sym
+    }
+    fn decode_bits(&mut self, bits: u8) -> u32 {
+        let sym = self.get_bits(bits);
+        self.update(1, sym);
+        sym
+    }
+    fn decode_symbol(&mut self, freqs: &[u32; 22]) -> u32 {
+        let bits = self.get_bits(16);
+        if bits > 65492 {
+            let sym = bits + MAX_MODEL_VAL - 65535;
+            self.update(1, bits);
+            if bits > 65536 {
+                self.error = true;
+            }
+            sym
+        } else {
+            let mut sym = 0usize;
+            while freqs[sym + 1] <= bits {
+                sym += 1;
+            }
+            self.update(freqs[sym + 1] - freqs[sym], freqs[sym]);
+            sym as u32
+        }
+    }
+}
+
+pub enum Coder<'a> {
+    Rice(RiceCoder<'a>),
+    Range(RangeCoder<'a>),
+}
+
+fn to_signed(val: u32) -> i32 {
+    if (val & 1) != 0 {
+        (val >> 1) as i32 + 1
+    } else {
+        -((val >> 1) as i32)
+    }
+}
+
+pub fn decode_mono_dummy(_c: &mut Coder, _l: &mut [i32]) -> DecoderResult<()> {
+    unreachable!();
+}
+pub fn decode_stereo_dummy(_c: &mut Coder, _l: &mut [i32], _r: &mut [i32]) -> DecoderResult<()> {
+    unreachable!();
+}
+
+fn new_k(val: u32) -> u8 {
+    (32 - (val | 1).leading_zeros()) as u8
+}
+fn rice_limit(k: u8) -> u32 { if k > 0 { 1 << (k + 4) } else { 0 } }
+fn decode_channel_0000(br: &mut BitReader, dst: &mut [i32]) -> DecoderResult<()> {
+    let (part01, part2) = dst.split_at_mut(64);
+    let (part0, part1) = part01.split_at_mut(5);
+    let mut pos = 0;
+    let mut last = [0u32; 64];
+    let mut sum = 0;
+    for el in part0.iter_mut() {
+        let val                         = br.read_code(UintCodeType::Rice(10))?;
+        sum += val;
+        *el = to_signed(val);
+        last[pos] = val;
+        pos += 1;
+    }
+    if part1.is_empty() {
+        return Ok(());
+    }
+    let mut k = new_k(sum / 10);
+    let mut w = 12;
+    for el in part1.iter_mut() {
+        let val                         = br.read_code(UintCodeType::Rice(k))?;
+        sum += val;
+        *el = to_signed(val);
+        k = new_k(sum / w);
+        w += 2;
+        last[pos] = val;
+        pos += 1;
+    }
+    if part2.is_empty() {
+        return Ok(());
+    }
+    let mut top_limit = rice_limit(k + 1) * 4;
+    let mut bot_limit = rice_limit(k)     * 4;
+    pos = 0;
+    for el in part2.iter_mut() {
+        let val                         = br.read_code(UintCodeType::Rice(k))?;
+        *el = to_signed(val);
+
+        sum = sum.wrapping_add(val.wrapping_sub(last[pos]));
+        while sum < bot_limit {
+            k -= 1;
+            bot_limit = rice_limit(k) * 4;
+            top_limit >>= 1;
+        }
+        while sum >= top_limit {
+            k += 1;
+            validate!(k < 24);
+            bot_limit = rice_limit(k) * 4;
+            top_limit <<= 1;
+        }
+
+        last[pos] = val;
+        pos = (pos + 1) & 63;
+    }
+
+    Ok(())
+}
+pub fn decode_mono_0000(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        decode_channel_0000(&mut rr.br, l)
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_0000(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        decode_channel_0000(&mut rr.br, l)?;
+        decode_channel_0000(&mut rr.br, r)?;
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+
+fn decode_value_3860(br: &mut BitReader, rice: &mut RiceParams) -> DecoderResult<i32> {
+    let overflow                        = br.read_code(UintCodeType::UnaryZeroes)?;
+
+    let val                             = (overflow << rice.k) | br.read(rice.k)?;
+    rice.update_old(val);
+    Ok(to_signed(val))
+}
+fn decode_value_3890(br: &mut BitReader, rice: &mut RiceParams) -> DecoderResult<i32> {
+    let mut overflow                    = br.read_code(UintCodeType::UnaryZeroes)?;
+    while overflow >= 16 {
+        overflow -= 16;
+        rice.k += 4;
+    }
+
+    let val                             = (overflow << rice.k) | br.read(rice.k)?;
+    rice.update_old(val);
+    Ok(to_signed(val))
+}
+pub fn decode_mono_3860(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+        }
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_mono_3890(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+        }
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3860(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3860(&mut rr.br, &mut rr.rice_y)?;
+        }
+        for el in r.iter_mut() {
+            *el = decode_value_3860(&mut rr.br, &mut rr.rice_x)?;
+        }
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3890(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Rice(ref mut rr) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3890(&mut rr.br, &mut rr.rice_y)?;
+        }
+        for el in r.iter_mut() {
+            *el = decode_value_3890(&mut rr.br, &mut rr.rice_x)?;
+        }
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+
+const COUNTS_3900: &[u32; 22] = &[
+        0, 14824, 28224, 39348, 47855, 53994, 58171, 60926,
+    62682, 63786, 64463, 64878, 65126, 65276, 65365, 65419,
+    65450, 65469, 65480, 65487, 65491, 65493
+];
+fn decode_value_3900(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+    let mut overflow = rc.decode_symbol(COUNTS_3900);
+    let k = if overflow == MAX_MODEL_VAL {
+            overflow = 0;
+            rc.decode_bits(5) as u8
+        } else {
+            rice.k.saturating_sub(1)
+        };
+    let base = rc.decode_bits(k);
+    let val = base + (overflow << k);
+    rice.update(val);
+    to_signed(val)
+}
+fn decode_value_3910(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+    let mut overflow = rc.decode_symbol(COUNTS_3900);
+    let k = if overflow == MAX_MODEL_VAL {
+            overflow = 0;
+            rc.decode_bits(5) as u8
+        } else {
+            rice.k.saturating_sub(1)
+        };
+    let base = if k <= 16 {
+            rc.decode_bits(k)
+        } else if k <= 32 {
+            let low = rc.decode_bits(k);
+            let high = rc.decode_bits(k - 16);
+            (high << (k - 16)) | low
+        } else {
+            rc.error = true;
+            return 0;
+        };
+    let val = base + (overflow << k);
+    rice.update(val);
+    to_signed(val)
+}
+pub fn decode_mono_3900(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3900(&mut rc.rc, &mut rc.rice_y);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_mono_3910(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3900(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3900(&mut rc.rc, &mut rc.rice_y);
+        }
+        rc.rc.normalise();
+        validate!(!rc.had_errors() && rc.rc.pos < rc.rc.src.len());
+        rc.rc.reset();
+        for el in r.iter_mut() {
+            *el = decode_value_3900(&mut rc.rc, &mut rc.rice_x);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3910(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+        }
+        rc.rc.normalise();
+        validate!(!rc.had_errors() && rc.rc.pos < rc.rc.src.len());
+        rc.rc.reset();
+        for el in r.iter_mut() {
+            *el = decode_value_3910(&mut rc.rc, &mut rc.rice_x);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3930(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+            *l = decode_value_3910(&mut rc.rc, &mut rc.rice_y);
+            *r = decode_value_3910(&mut rc.rc, &mut rc.rice_x);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+
+const COUNTS_3990: &[u32; 22] = &[
+        0, 19578, 36160, 48417, 56323, 60899, 63265, 64435,
+    64971, 65232, 65351, 65416, 65447, 65466, 65476, 65482,
+    65485, 65488, 65490, 65491, 65492, 65493
+];
+fn decode_value_3990(rc: &mut ARangeCoder, rice: &mut RiceParams) -> i32 {
+    let pivot = (rice.sum >> 5).max(1);
+    let mut overflow = rc.decode_symbol(COUNTS_3990);
+    if overflow == MAX_MODEL_VAL {
+        overflow  = rc.decode_bits(16) << 16;
+        overflow |= rc.decode_bits(16);
+    }
+    let base = if pivot < (1 << 16) {
+            rc.decode_freq(pivot)
+        } else {
+            let shift = (16 - pivot.trailing_zeros()) as u8;
+            let hi = rc.decode_freq((pivot >> shift) + 1);
+            let lo = rc.decode_bits(shift);
+            (hi << shift) | lo
+        };
+    let val = base + overflow * pivot;
+    rice.update(val);
+    to_signed(val)
+}
+pub fn decode_mono_3990(c: &mut Coder, l: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for el in l.iter_mut() {
+            *el = decode_value_3990(&mut rc.rc, &mut rc.rice_y);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
+pub fn decode_stereo_3990(c: &mut Coder, l: &mut [i32], r: &mut [i32]) -> DecoderResult<()> {
+    if let Coder::Range(ref mut rc) = c {
+        for (l, r) in l.iter_mut().zip(r.iter_mut()) {
+            *l = decode_value_3990(&mut rc.rc, &mut rc.rice_y);
+            *r = decode_value_3990(&mut rc.rc, &mut rc.rice_x);
+        }
+        validate!(!rc.had_errors());
+        Ok(())
+    } else {
+        Err(DecoderError::Bug)
+    }
+}
diff --git a/nihav-llaudio/src/codecs/flac.rs b/nihav-llaudio/src/codecs/flac.rs
new file mode 100644 (file)
index 0000000..55cd6bb
--- /dev/null
@@ -0,0 +1,527 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+const MAX_SAMPLES: usize = 32768;
+
+#[derive(Clone,Copy,PartialEq)]
+enum StereoMode {
+    Normal,
+    LeftSide,
+    SideRight,
+    MidSide,
+}
+
+struct FlacDecoder {
+    ainfo:          NAAudioInfo,
+    chmap:          NAChannelMap,
+    min_blk_size:   usize,
+    max_blk_size:   usize,
+    min_frm_size:   usize,
+    max_frm_size:   usize,
+    channels:       u8,
+    bits:           u8,
+    srate:          u32,
+    residues:       [Vec<i32>; 8],
+}
+
+fn decode_partition(br: &mut BitReader, dst: &mut [i32], k: u8) -> DecoderResult<()> {
+    for el in dst.iter_mut() {
+        let val                         = br.read_code(UintCodeType::Rice(k))?;
+        if (val & 1) == 0 {
+            *el = (val >> 1) as i32;
+        } else {
+            *el = -(((val + 1) >> 1) as i32);
+        }
+    }
+    Ok(())
+}
+
+fn decode_residual(br: &mut BitReader, dst: &mut [i32], order: usize) -> DecoderResult<()> {
+    let mode                            = br.read(2)?;
+    validate!(mode < 2);
+    let rice_k = if mode == 0 { 4 } else { 5 };
+    let esc = (1 << rice_k) - 1;
+
+    let num_partitions                  = 1 << br.read(4)?;
+    let tot_size = dst.len() + order;
+    validate!((tot_size % num_partitions) == 0);
+    let psize = tot_size / num_partitions;
+    validate!(psize >= order);
+    let mut off = psize - order;
+    let k                               = br.read(rice_k)? as u8;
+    if k != esc {
+        decode_partition(br, &mut dst[..off], k)?;
+    } else {
+        let bits                        = br.read(5)? as u8;
+        for el in dst.iter_mut().take(off) {
+            *el                         = br.read_s(bits)?;
+        }
+    }
+    for _ in 1..num_partitions {
+        let k                           = br.read(rice_k)? as u8;
+        if k != esc {
+            decode_partition(br, &mut dst[off..][..psize], k)?;
+        } else {
+            let bits                    = br.read(5)? as u8;
+            for el in dst[off..].iter_mut().take(psize) {
+                *el                     = br.read_s(bits)?;
+            }
+        }
+        off += psize;
+    }
+
+    Ok(())
+}
+
+fn apply_fixed_predictor(dst: &mut [i32], order: usize) {
+    match order {
+        1 => {
+            let mut last = dst[0];
+            for el in dst.iter_mut().skip(1) {
+                *el += last;
+                last = *el;
+            }
+        },
+        2 => {
+            let mut last0 = dst[1];
+            let mut last1 = last0 - dst[0];
+            for el in dst.iter_mut().skip(2) {
+                last1 += *el;
+                last0 += last1;
+                *el = last0;
+            }
+        },
+        3 => {
+            let mut last0 = dst[2];
+            let mut last1 = last0 - dst[1];
+            let mut last2 = last1 - dst[1] + dst[0];
+            for el in dst.iter_mut().skip(3) {
+                last2 += *el;
+                last1 += last2;
+                last0 += last1;
+                *el = last0;
+            }
+        },
+        4 => {
+            let mut last0 = dst[3];
+            let mut last1 = last0 - dst[2];
+            let mut last2 = last1 - dst[2] + dst[1];
+            let mut last3 = last2 - dst[2] + 2 * dst[1] - dst[0];
+            for el in dst.iter_mut().skip(4) {
+                last3 += *el;
+                last2 += last3;
+                last1 += last2;
+                last0 += last1;
+                *el = last0;
+            }
+        },
+        _ => unreachable!(),
+    };
+}
+
+fn apply_lpc(dst: &mut [i32], filt: &[i32; 16], order: usize, shift: u8) {
+    for i in order..dst.len() {
+        let mut sum = 0i64;
+        for (coef, filt) in dst[i - order..].iter().take(order).zip(filt.iter()) {
+            sum += i64::from(*coef) * i64::from(*filt);
+        }
+        dst[i] += (sum >> shift) as i32;
+    }
+}
+
+impl FlacDecoder {
+    fn new() -> Self {
+        Self {
+            ainfo:          NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+            chmap:          NAChannelMap::new(),
+            min_blk_size:   0,
+            max_blk_size:   0,
+            min_frm_size:   0,
+            max_frm_size:   0,
+            channels:       0,
+            bits:           0,
+            srate:          0,
+            residues:       [vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+                             vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+                             vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES],
+                             vec![0; MAX_SAMPLES], vec![0; MAX_SAMPLES]],
+        }
+    }
+    fn apply_chmod(&mut self, blocksize: usize, chmod: StereoMode) {
+        match chmod {
+            StereoMode::Normal => {},
+            StereoMode::LeftSide => {
+                for i in 0..blocksize {
+                    self.residues[1][i] = self.residues[0][i].wrapping_sub(self.residues[1][i]);
+                }
+            },
+            StereoMode::SideRight => {
+                for i in 0..blocksize {
+                    self.residues[0][i] = self.residues[0][i].wrapping_add(self.residues[1][i]);
+                }
+            },
+            StereoMode::MidSide => {
+                for i in 0..blocksize {
+                    let r = self.residues[0][i].wrapping_sub(self.residues[1][i] >> 1);
+                    self.residues[0][i] = self.residues[1][i].wrapping_add(r);
+                    self.residues[1][i] = r;
+                }
+            },
+        };
+    }
+    fn decode_subframe(&mut self, br: &mut BitReader, channel: usize, blocksize: usize, mut samp_bits: u8) -> DecoderResult<()> {
+        let marker                      = br.read(1)?;
+        validate!(marker == 0);
+        let sftype                      = br.read(6)?;
+
+        if br.read_bool()? {
+            let nbits                   = br.read_code(UintCodeType::UnaryZeroes)?;
+            validate!(nbits < 32 && samp_bits > nbits as u8);
+            samp_bits -= nbits as u8;
+        }
+
+        let dst = &mut self.residues[channel][..blocksize];
+        match sftype {
+            0x00 => {
+                let val                 = br.read_s(samp_bits)?;
+                for el in dst.iter_mut() {
+                    *el = val;
+                }
+            },
+            0x01 => {
+                for el in dst.iter_mut() {
+                    *el                 = br.read_s(samp_bits)?;
+                }
+            },
+            0x08..=0x0C => {
+                let order = (sftype - 0x08) as usize;
+                for el in dst.iter_mut().take(order) {
+                    *el                 = br.read_s(samp_bits)?;
+                }
+                decode_residual(br, &mut dst[order..], order)?;
+                if order > 0 {
+                    apply_fixed_predictor(dst, order);
+                }
+            },
+            0x20..=0x3F => {
+                let order = (sftype - 0x20) as usize + 1;
+                for el in dst.iter_mut().take(order) {
+                    *el                 = br.read_s(samp_bits)?;
+                }
+                let precision           = br.read(4)? as u8 + 1;
+                validate!(precision < 16);
+                let shift               = br.read(5)? as u8;
+                let mut filter = [0i32; 16];
+                for el in filter[..order].iter_mut().rev() {
+                    *el                 = br.read_s(precision)?;
+                }
+                decode_residual(br, &mut dst[order..], order)?;
+                apply_lpc(dst, &filter, order, shift);
+            },
+            _ => return Err(DecoderError::InvalidData),
+        };
+
+        Ok(())
+    }
+}
+
+impl NADecoder for FlacDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        const DEFAULT_CHANNEL_MAPS: [&str; 8] = [
+            "C",
+            "L,R",
+            "L,R,C",
+            "L,R,Ls,Rs",
+            "L,R,C,Ls,Rs",
+            "L,R,C,LFE,Ls,Rs",
+            "L,R,C,LFE,Cs,Ls,Rs",
+            "L,R,C,LFE,Ls,Rs,Lss,Rss"
+        ];
+        if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+            if let Some(buf) = info.get_extradata() {
+                validate!(buf.len() >= 22);
+
+                let mut mr = MemoryReader::new_read(&buf);
+                let mut br = ByteReader::new(&mut mr);
+
+                self.min_blk_size       = br.read_u16be()? as usize;
+                self.max_blk_size       = br.read_u16be()? as usize;
+                self.min_frm_size       = br.read_u24be()? as usize;
+                self.max_frm_size       = br.read_u24be()? as usize;
+                let tmp                 = br.read_u64be()?;
+                self.srate      = (tmp >> 44) as u32;
+                self.channels   = (((tmp >> 41) & 7) + 1) as u8;
+                self.bits       = (((tmp >> 36) & 0x1F) + 1) as u8;
+                //let tot_samples        = tmp & ((1 << 36) - 1);
+
+                self.chmap = NAChannelMap::from_str(DEFAULT_CHANNEL_MAPS[(self.channels - 1) as usize]).unwrap();
+                let fmt = match self.bits {
+                        8 | 12 | 16 => SND_S16P_FORMAT,
+                        24 => SND_S32P_FORMAT,
+                        _ => return Err(DecoderError::NotImplemented),
+                    };
+
+                self.ainfo = NAAudioInfo::new(self.srate, self.channels as u8, fmt, self.max_blk_size.max(1));
+                Ok(())
+            } else {
+                Err(DecoderError::InvalidData)
+            }
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() >= 9.max(self.min_frm_size));
+
+            let ref_crc = read_u16be(&pktbuf[pktbuf.len() - 2..]).unwrap_or(0);
+            let mut crc = 0;
+            for el in pktbuf.iter().take(pktbuf.len() - 2) {
+                crc = update_crc16(crc, *el);
+            }
+            if crc != ref_crc {
+                return Err(DecoderError::ChecksumError);
+            }
+
+            let mut br = BitReader::new(&pktbuf, BitReaderMode::BE);
+
+            let sync                    = br.read(14)?;
+            validate!(sync == 0x3FFE);
+                                          br.skip(1)?;
+            let _blocking               = br.read(1)?;
+            let bsize_idx               = br.read(4)?;
+            let srate_idx               = br.read(4)?;
+            let chan_idx                = br.read(4)?;
+            let bits_idx                = br.read(3)?;
+                                          br.skip(1)?;
+            // UTF-8 encoded block or sample number
+            let byte                    = br.read(8)? as u8;
+            let len = (!byte).leading_zeros();
+            validate!(len <= 5 && len != 1);
+            if len > 1 {
+                for _ in 1..len {
+                    let byte            = br.read(8)?;
+                    validate!((byte & 0xC0) == 0x80);
+                }
+            }
+            let blocksize = match bsize_idx {
+                    0       => return Err(DecoderError::InvalidData),
+                    1       => 192,
+                    2..=5   => 576 << (bsize_idx - 2),
+                    6       =>            br.read(8)? as usize + 1,
+                    7       =>            br.read(16)? as usize + 1,
+                    _       => 256 << (bsize_idx - 8),
+                };
+            let srate = match srate_idx {
+                     0 => self.srate,
+                     1 => 88200,
+                     2 => 176400,
+                     3 => 192000,
+                     4 => 8000,
+                     5 => 16000,
+                     6 => 22050,
+                     7 => 24000,
+                     8 => 32000,
+                     9 => 44100,
+                    10 => 48000,
+                    11 => 96000,
+                    12 =>                 br.read(8)? * 1000,
+                    13 =>                 br.read(16)?,
+                    14 =>                 br.read(16)? * 10,
+                     _ => return Err(DecoderError::InvalidData),
+                };
+            validate!(srate != 0 && srate == self.srate);
+            let (channels, chmod) = match chan_idx {
+                    0..=7 => (chan_idx as u8 + 1, StereoMode::Normal),
+                    8     => (2, StereoMode::LeftSide),
+                    9     => (2, StereoMode::SideRight),
+                    10    => (2, StereoMode::MidSide),
+                    _     => return Err(DecoderError::InvalidData),
+                };
+            validate!(channels == self.channels);
+            let bits = match bits_idx {
+                    0 => self.bits,
+                    1 => 8,
+                    2 => 12,
+                    4 => 16,
+                    5 => 20,
+                    6 => 24,
+                    _ => return Err(DecoderError::InvalidData),
+                };
+            validate!(bits == self.bits);
+
+            let end = br.tell() / 8;
+            let ref_crc                 = br.read(8)? as u8;
+            let mut crc = 0;
+            for el in pktbuf.iter().take(end) {
+                crc = update_crc8(crc, *el);
+            }
+            if crc != ref_crc {
+                return Err(DecoderError::ChecksumError);
+            }
+
+            for ch in 0..(channels as usize) {
+                let samp_bits = match (chmod, ch) {
+                        (StereoMode::LeftSide,  1) |
+                        (StereoMode::SideRight, 0) |
+                        (StereoMode::MidSide,   1) => self.bits + 1,
+                        _ => self.bits,
+                    };
+                validate!(samp_bits <= 32);
+                self.decode_subframe(&mut br, ch, blocksize, samp_bits)?;
+            }
+            if channels == 2 {
+                self.apply_chmod(blocksize, chmod);
+            }
+
+            let mut abuf = alloc_audio_buffer(self.ainfo, blocksize, self.chmap.clone())?;
+            let postshift = if self.bits == 24 { 8 } else { 16 - self.bits };
+            match abuf {
+                NABufferType::AudioI16(ref mut adata) => {
+                    let stride = adata.get_stride();
+                    let dst = adata.get_data_mut().unwrap();
+                    let mut off = 0;
+                    for residues in self.residues.iter().take(channels as usize) {
+                        let dst = &mut dst[off..][..blocksize];
+                        for (dst, src) in dst.iter_mut().zip(residues.iter()) {
+                            *dst = (*src << postshift) as i16;
+                        }
+                        off += stride;
+                    }
+                },
+                NABufferType::AudioI32(ref mut adata) => {
+                    let stride = adata.get_stride();
+                    let dst = adata.get_data_mut().unwrap();
+                    let mut off = 0;
+                    for residues in self.residues.iter().take(channels as usize) {
+                        let dst = &mut dst[off..][..blocksize];
+                        for (dst, src) in dst.iter_mut().zip(residues.iter()) {
+                            *dst = *src << postshift;
+                        }
+                        off += stride;
+                    }
+                },
+                _ => unreachable!(),
+            };
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+            frm.set_duration(Some(blocksize as u64));
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for FlacDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(FlacDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::llaudio_register_all_decoders;
+    use crate::llaudio_register_all_demuxers;
+    #[test]
+    fn test_flac() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("flac", "flac", "assets/LLaudio/luckynight.flac", Some(6), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xe689787a, 0x032a98f7, 0xeb6e64f4, 0xfa652132]));
+    }
+}
+
+fn update_crc8(crc: u8, byte: u8) -> u8 {
+    CRC8_TABLE[(crc ^ byte) as usize]
+}
+
+fn update_crc16(crc: u16, byte: u8) -> u16 {
+    (crc << 8) ^ CRC16_TABLE[(((crc >> 8) as u8) ^ byte) as usize]
+}
+
+const CRC8_TABLE: [u8; 256] = [
+    0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15,
+       0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D,
+       0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65,
+       0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D,
+       0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5,
+       0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD,
+       0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85,
+       0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD,
+       0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2,
+       0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA,
+       0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2,
+       0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A,
+       0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32,
+       0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A,
+       0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42,
+       0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A,
+       0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C,
+       0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4,
+       0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC,
+       0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4,
+       0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C,
+       0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44,
+       0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C,
+       0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34,
+       0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B,
+       0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63,
+       0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B,
+       0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13,
+       0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB,
+       0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83,
+       0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB,
+    0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3
+];
+
+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
+];
diff --git a/nihav-llaudio/src/codecs/mod.rs b/nihav-llaudio/src/codecs/mod.rs
new file mode 100644 (file)
index 0000000..5cc1769
--- /dev/null
@@ -0,0 +1,39 @@
+use nihav_core::codecs::*;
+
+macro_rules! validate {
+    ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DecoderError::InvalidData); } };
+}
+
+#[cfg(feature="decoder_ape")]
+pub mod ape;
+#[cfg(feature="decoder_ape")]
+mod apepred;
+#[cfg(feature="decoder_ape")]
+mod apereader;
+
+#[cfg(feature="decoder_flac")]
+pub mod flac;
+
+#[cfg(feature="decoder_tta")]
+pub mod tta;
+
+#[cfg(feature="decoder_wavpack")]
+pub mod wavpack;
+
+const LL_AUDIO_CODECS: &[DecoderInfo] = &[
+#[cfg(feature="decoder_ape")]
+    DecoderInfo { name: "ape", get_decoder: ape::get_decoder },
+#[cfg(feature="decoder_flac")]
+    DecoderInfo { name: "flac", get_decoder: flac::get_decoder },
+#[cfg(feature="decoder_tta")]
+    DecoderInfo { name: "tta", get_decoder: tta::get_decoder },
+#[cfg(feature="decoder_wavpack")]
+    DecoderInfo { name: "wavpack", get_decoder: wavpack::get_decoder },
+];
+
+/// Registers all available codecs provided by this crate.
+pub fn llaudio_register_all_decoders(rd: &mut RegisteredDecoders) {
+    for decoder in LL_AUDIO_CODECS.iter() {
+        rd.add_decoder(decoder.clone());
+    }
+}
diff --git a/nihav-llaudio/src/codecs/tta.rs b/nihav-llaudio/src/codecs/tta.rs
new file mode 100644 (file)
index 0000000..03eb515
--- /dev/null
@@ -0,0 +1,415 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+#[derive(Default)]
+struct Filter {
+    predictor:  i32,
+    error:      i32,
+    round:      i32,
+    shift:      u8,
+    qm:         [i32; 8],
+    dx:         [i32; 8],
+    dl:         [i32; 8],
+}
+
+impl Filter {
+    fn reset(&mut self, bpp: u8) {
+        const SHIFTS: [u8; 3] = [10, 9, 10];
+        self.shift = SHIFTS[(bpp - 1) as usize];
+        self.round = (1 << self.shift) >> 1;
+        self.error = 0;
+        self.qm = [0; 8];
+        self.dx = [0; 8];
+        self.dl = [0; 8];
+        self.predictor = 0;
+    }
+    fn hybrid_filt(&mut self, delta: i32) -> i32 {
+        if self.error < 0 {
+            for (qm, dx) in self.qm.iter_mut().zip(self.dx.iter()) {
+                *qm -= *dx;
+            }
+        } else if self.error > 0 {
+            for (qm, dx) in self.qm.iter_mut().zip(self.dx.iter()) {
+                *qm += *dx;
+            }
+        }
+
+        let mut sum = self.round;
+        for (dl, qm) in self.dl.iter().zip(self.qm.iter()) {
+            sum = sum.wrapping_add(*dl * *qm);
+        }
+        self.error = delta;
+        let val = (sum >> self.shift) + delta;
+
+        for i in 0..4 {
+            self.dx[i] = self.dx[i + 1];
+            self.dl[i] = self.dl[i + 1];
+        }
+        self.dx[4] =  (self.dl[4] >> 30) | 1;
+        self.dx[5] = ((self.dl[5] >> 30) | 2) & !1;
+        self.dx[6] = ((self.dl[6] >> 30) | 2) & !1;
+        self.dx[7] = ((self.dl[7] >> 30) | 4) & !3;
+        self.dl[4] = -self.dl[5];
+        self.dl[5] = -self.dl[6];
+        self.dl[6] = val - self.dl[7];
+        self.dl[7] = val;
+        self.dl[5] += self.dl[6];
+        self.dl[4] += self.dl[5];
+
+        val
+    }
+    fn static_pred(&mut self, bpp: u8, mut val: i32) -> i32 {
+        val += match bpp {
+                0     => ((i64::from(self.predictor) * 15) >> 4) as i32,
+                1 | 2 => ((i64::from(self.predictor) * 31) >> 5) as i32,
+                _     => self.predictor,
+            };
+        self.predictor = val;
+        val
+    }
+}
+
+struct RiceDecoder {
+    k:      u8,
+    sum:    u32,
+}
+
+impl RiceDecoder {
+    fn new() -> Self {
+        let k = 10;
+        Self {
+            k, sum: RiceDecoder::limit(k)
+        }
+    }
+    fn reset(&mut self) {
+        self.k = 10;
+        self.sum = RiceDecoder::limit(self.k);
+    }
+    fn limit(k: u8) -> u32 { 1 << (k + 4).min(31) }
+    fn update(&mut self, val: u32) {
+        self.sum -= self.sum >> 4;
+        self.sum += val;
+        if self.k > 0 && self.sum < Self::limit(self.k) {
+            self.k -= 1;
+        } else if self.sum > Self::limit(self.k + 1) {
+            self.k += 1;
+        }
+    }
+}
+
+trait Output {
+    fn set(&mut self, val: i32);
+}
+
+impl Output for i16 {
+    fn set(&mut self, val: i32) { *self = val as i16; }
+}
+impl Output for i32 {
+    fn set(&mut self, val: i32) { *self = val; }
+}
+
+struct ChannelDecoder {
+    filt:       Filter,
+    rice0:      RiceDecoder,
+    rice1:      RiceDecoder,
+    offset:     usize,
+    sample:     i32,
+}
+
+impl ChannelDecoder {
+    fn new() -> Self {
+        Self {
+            filt:       Filter::default(),
+            rice0:      RiceDecoder::new(),
+            rice1:      RiceDecoder::new(),
+            offset:     0,
+            sample:     0,
+        }
+    }
+}
+
+struct TTADecoder {
+    ainfo:      NAAudioInfo,
+    chmap:      NAChannelMap,
+    bpp:        u8,
+    framelen:   u32,
+    nsamples:   u32,
+    ch_dec:     Vec<ChannelDecoder>,
+}
+
+impl TTADecoder {
+    fn new() -> Self {
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+            chmap:      NAChannelMap::new(),
+            bpp:        0,
+            framelen:   0,
+            nsamples:   0,
+            ch_dec:     Vec::new(),
+        }
+    }
+    fn decode_frame<T: Output>(&mut self, br: &mut BitReader, dst: &mut [T], stride: usize) -> DecoderResult<bool> {
+        for (i, chdec) in self.ch_dec.iter_mut().enumerate() {
+            chdec.offset = i * stride;
+            chdec.rice0.reset();
+            chdec.rice1.reset();
+            chdec.filt.reset(self.bpp);
+        }
+
+        let channels = self.ch_dec.len();
+        let tail_len = self.nsamples % self.framelen;
+
+        for sample in 0..self.framelen {
+            for chdec in self.ch_dec.iter_mut() {
+                let pfx                 = br.read_code(UintCodeType::UnaryOnes)?;
+                let (k, pfx, level1) = if pfx == 0 {
+                        (chdec.rice0.k, 0, false)
+                    } else {
+                        (chdec.rice1.k, pfx - 1, true)
+                    };
+                let mut val             = (pfx << k) | br.read(k)?;
+                if level1 {
+                    chdec.rice1.update(val);
+                    val += 1 << chdec.rice0.k;
+                }
+                chdec.rice0.update(val);
+                let delta = if (val & 1) == 0 {
+                        -((val >> 1) as i32)
+                    } else {
+                        ((val + 1) >> 1) as i32
+                    };
+                let hval = chdec.filt.hybrid_filt(delta);
+                chdec.sample = chdec.filt.static_pred(self.bpp, hval);
+            }
+            if channels > 1 {
+                self.ch_dec[channels - 1].sample += self.ch_dec[channels - 2].sample / 2;
+                let mut last = self.ch_dec[channels - 1].sample;
+                for chdec in self.ch_dec.iter_mut().rev().skip(1) {
+                    chdec.sample = last - chdec.sample;
+                    last = chdec.sample;
+                }
+            }
+            for chdec in self.ch_dec.iter_mut() {
+                dst[chdec.offset].set(chdec.sample);
+                chdec.offset += 1;
+            }
+            if (tail_len > 0) && (sample == tail_len - 1) && (br.left() < 40) {
+                return Ok(false);
+            }
+        }
+
+        Ok(true)
+    }
+}
+
+fn check_crc(buf: &[u8]) -> bool {
+    if buf.len() <= 4 {
+        return false;
+    }
+    let mut crc = 0xFFFFFFFF;
+    let ref_crc = read_u32le(&buf[buf.len() - 4..]).unwrap_or(0);
+    for el in buf.iter().take(buf.len() - 4) {
+        crc = CRC32_TAB[(crc as u8 ^ *el) as usize] ^ (crc >> 8);
+    }
+    crc == !ref_crc
+}
+
+impl NADecoder for TTADecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+            if let Some(buf) = info.get_extradata() {
+                if !check_crc(&buf) {
+                    return Err(DecoderError::ChecksumError);
+                }
+                let mut mr = MemoryReader::new_read(&buf);
+                let mut br = ByteReader::new(&mut mr);
+                let tag                 = br.read_tag()?;
+                validate!(&tag == b"TTA1");
+                let afmt                = br.read_u16le()?;
+                if afmt != 1 {
+                    return Err(DecoderError::NotImplemented);
+                }
+                let channels            = br.read_u16le()?;
+                validate!(channels > 0 && channels < 256);
+                let bpp                 = br.read_u16le()?;
+                validate!(bpp > 0 && bpp <= 32);
+                let srate               = br.read_u32le()?;
+                validate!(srate > 256 && srate < 1048576);
+                self.nsamples           = br.read_u32le()?;
+                validate!(self.nsamples > 0);
+
+                self.framelen = srate * 256 / 245;
+
+                self.chmap = if channels == 1 {
+                        NAChannelMap::from_str("C").unwrap()
+                    } else if channels == 2 {
+                        NAChannelMap::from_str("L,R").unwrap()
+                    } else {
+                        return Err(DecoderError::NotImplemented);
+                    };
+                let fmt = match bpp {
+                         8 | 16 => SND_S16P_FORMAT,
+                        24 | 32 => SND_S32P_FORMAT,
+                        _ => return Err(DecoderError::NotImplemented),
+                    };
+                self.bpp = (bpp / 8) as u8;
+                self.ch_dec = Vec::with_capacity(channels as usize);
+                for _ in 0..channels {
+                    self.ch_dec.push(ChannelDecoder::new());
+                }
+
+                self.ainfo = NAAudioInfo::new(srate, channels as u8, fmt, self.framelen as usize);
+                Ok(())
+            } else {
+                Err(DecoderError::InvalidData)
+            }
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() > 4);
+            if !check_crc(&pktbuf) {
+                return Err(DecoderError::ChecksumError);
+            }
+
+            let mut br = BitReader::new(&pktbuf, BitReaderMode::LE);
+
+            let mut abuf = alloc_audio_buffer(self.ainfo, self.framelen as usize, self.chmap.clone())?;
+            let duration = match abuf {
+                    NABufferType::AudioI16(ref mut adata) => {
+                        let stride = adata.get_stride();
+                        let dst = adata.get_data_mut().unwrap();
+                        let not_last = self.decode_frame(&mut br, dst, stride)?;
+                        if not_last {
+                            self.framelen
+                        } else {
+                            adata.truncate((self.nsamples % self.framelen) as usize);
+                            self.nsamples % self.framelen
+                        }
+                    },
+                    NABufferType::AudioI32(ref mut adata) => {
+                        let stride = adata.get_stride();
+                        let dst = adata.get_data_mut().unwrap();
+                        let not_last = self.decode_frame(&mut br, dst, stride)?;
+                        if not_last {
+                            self.framelen
+                        } else {
+                            adata.truncate((self.nsamples % self.framelen) as usize);
+                            self.nsamples % self.framelen
+                        }
+                    },
+                    _ => unreachable!(),
+                };
+
+            let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+            frm.set_duration(Some(u64::from(duration)));
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for TTADecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(TTADecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::llaudio_register_all_decoders;
+    use crate::llaudio_register_all_demuxers;
+    #[test]
+    fn test_tta() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("tta", "tta", "assets/LLaudio/luckynight.tta", Some(3), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xce0fe9c4, 0xa69eefda, 0xe182008c, 0xe941db3f]));
+    }
+}
+
+const CRC32_TAB: [u32; 256] = [
+       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+    0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+    0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+    0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+    0x1db71064, 0x6ab020f2,    0xf3b97148, 0x84be41de,
+    0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+    0x14015c4f, 0x63066cd9,    0xfa0f3d63, 0x8d080df5,
+    0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+    0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+    0x35b5a8fa, 0x42b2986c,    0xdbbbc9d6, 0xacbcf940,
+    0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+    0x21b4f4b5, 0x56b3c423,    0xcfba9599, 0xb8bda50f,
+    0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+    0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+    0x76dc4190, 0x01db7106,    0x98d220bc, 0xefd5102a,
+    0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+    0x7f6a0dbb, 0x086d3d2d,    0x91646c97, 0xe6635c01,
+    0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+    0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+    0x65b0d9c6, 0x12b7e950,    0x8bbeb8ea, 0xfcb9887c,
+    0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+    0x4adfa541, 0x3dd895d7,    0xa4d1c46d, 0xd3d6f4fb,
+    0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+    0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+    0x5005713c, 0x270241aa,    0xbe0b1010, 0xc90c2086,
+    0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+    0x59b33d17, 0x2eb40d81,    0xb7bd5c3b, 0xc0ba6cad,
+    0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+    0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+    0xe3630b12, 0x94643b84,    0x0d6d6a3e, 0x7a6a5aa8,
+    0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+    0xf762575d, 0x806567cb,    0x196c3671, 0x6e6b06e7,
+    0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+    0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+    0xd6d6a3e8, 0xa1d1937e,    0x38d8c2c4, 0x4fdff252,
+    0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+    0xdf60efc3, 0xa867df55,    0x316e8eef, 0x4669be79,
+    0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+    0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+    0xc5ba3bbe, 0xb2bd0b28,    0x2bb45a92, 0x5cb36a04,
+    0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+    0x9c0906a9, 0xeb0e363f,    0x72076785, 0x05005713,
+    0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+    0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+    0x86d3d2d4, 0xf1d4e242,    0x68ddb3f8, 0x1fda836e,
+    0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+    0x8f659eff, 0xf862ae69,    0x616bffd3, 0x166ccf45,
+    0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+    0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+    0xaed16a4a, 0xd9d65adc,    0x40df0b66, 0x37d83bf0,
+    0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+    0xbad03605, 0xcdd70693,    0x54de5729, 0x23d967bf,
+    0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+    0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+];
diff --git a/nihav-llaudio/src/codecs/wavpack.rs b/nihav-llaudio/src/codecs/wavpack.rs
new file mode 100644 (file)
index 0000000..07aef40
--- /dev/null
@@ -0,0 +1,1195 @@
+use nihav_core::codecs::*;
+use nihav_core::io::byteio::*;
+use nihav_core::io::bitreader::*;
+use nihav_core::io::intcode::*;
+
+const SAMPLE_RATES: [u32; 15] = [
+     6000,  8000,  9600, 11025, 12000, 16000,  22050, 24000,
+    32000, 44100, 48000, 64000, 88200, 96000, 192000
+];
+const WV_FLAG_MONO: u32         = 1 <<  2;
+const WV_FLAG_HYBRID: u32       = 1 <<  3;
+const WV_FLAG_JSTEREO: u32      = 1 <<  4;
+//const WV_FLAG_CH_DECORR: u32    = 1 <<  5;
+//const WV_FLAG_HYB_NOISE_SHAPING: u32 = 1 <<  6;
+const WV_FLAG_FLOATS: u32       = 1 <<  7;
+const WV_FLAG_EXT_INTEGERS: u32 = 1 <<  8;
+const WV_FLAG_HYB_BITRATE: u32  = 1 <<  9;
+//const WV_FLAG_HYB_BALANCED_NOISE: u32 = 1 << 10;
+const WV_FLAG_START_BLOCK: u32  = 1 << 11;
+const WV_FLAG_END_BLOCK: u32    = 1 << 12;
+//const WV_FLAG_HAS_CRC: u32      = 1 << 28;
+const WV_FLAG_FALSE_STEREO: u32 = 1 << 30;
+const WV_FLAG_DSD_AUDIO: u32    = 1 << 31;
+
+const WV_STREAM_FLAGS: u32 = 0x8000018B;
+
+#[derive(Clone,Copy,Default)]
+struct WVHeader {
+    size:           usize,
+    ver:            u16,
+    tot_samples:    u64,
+    block_index:    u64,
+    block_samples:  u32,
+    flags:          u32,
+    crc:            u32,
+}
+
+const WV_HEADER_SIZE: usize = 32;
+
+impl WVHeader {
+    fn parse(src: &[u8]) -> DecoderResult<Self> {
+        let mut mr = MemoryReader::new_read(src);
+        let mut br = ByteReader::new(&mut mr);
+        let tag                         = br.read_tag()?;
+        validate!(&tag == b"wvpk");
+        let mut hdr = Self::default();
+        hdr.size                        = br.read_u32le()? as usize;
+        validate!(hdr.size >= 24);
+        hdr.ver                         = br.read_u16le()?;
+        validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
+        let top_idx                     = br.read_byte()?;
+        let top_samps                   = br.read_byte()?;
+        hdr.tot_samples                 = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
+        hdr.block_index                 = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
+        hdr.block_samples               = br.read_u32le()?;
+        hdr.flags                       = br.read_u32le()?;
+        hdr.crc                         = br.read_u32le()?;
+        Ok(hdr)
+    }
+    fn stream_eq(&self, rval: &Self) -> bool {
+        self.ver == rval.ver &&
+        (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
+    }
+    fn block_eq(&self, rval: &Self) -> bool {
+        self.stream_eq(rval) && self.block_index == rval.block_index &&
+        self.tot_samples == rval.tot_samples &&
+        self.block_samples == rval.block_samples
+    }
+    fn is_start_block(&self) -> bool {
+        (self.flags & WV_FLAG_START_BLOCK) != 0
+    }
+    fn is_end_block(&self) -> bool {
+        (self.flags & WV_FLAG_END_BLOCK) != 0
+    }
+    fn get_num_channels(&self) -> u8 {
+        if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
+    }
+    fn get_sample_rate(&self) -> u32 {
+        let idx = ((self.flags >> 23) & 0xF) as usize;
+        if idx != 15 {
+            SAMPLE_RATES[idx]
+        } else {
+            0
+        }
+    }
+    fn get_size(&self) -> usize {
+        self.size - (WV_HEADER_SIZE - 8)
+    }
+    fn get_bits(&self) -> u8 {
+        (((self.flags & 3) + 1) * 8) as u8
+    }
+}
+
+fn wv_log2lin(val: i32) -> i32 {
+    let sign = val < 0;
+    let aval = val.abs();
+    let mant = 0x100 | i32::from(WV_EXP_TABLE[(aval & 0xFF) as usize]);
+    let exp = aval >> 8;
+    let aval = if exp >= 9 {
+            mant << (exp - 9)
+        } else {
+            mant >> (9 - exp)
+        };
+    if !sign {
+        aval
+    } else {
+        -aval
+    }
+}
+
+fn wv_lin2log(val: u32) -> u32 {
+    if val == 0 {
+        0
+    } else if val == 1 {
+        0x100
+    } else {
+        let val = val + (val >> 9);
+        let bits = 32 - val.leading_zeros();
+        if bits < 9 {
+            (bits << 8) + u32::from(WV_LOG_TABLE[((val << (9 - bits)) & 0xFF) as usize])
+        } else {
+            (bits << 8) + u32::from(WV_LOG_TABLE[((val >> (bits - 9)) & 0xFF) as usize])
+        }
+    }
+}
+
+#[derive(Clone,Copy,Default)]
+struct Decorrelator {
+    delta:      i32,
+    value:      i32,
+    weight_a:   i32,
+    weight_b:   i32,
+    samples_a:  [i32; 8],
+    samples_b:  [i32; 8],
+}
+
+impl Decorrelator {
+    fn decorrelate_mono(&mut self, l: i32, pos: usize) -> i32 {
+        let mode = self.value;
+        let (a, npos) = if mode > 8 {
+                let a = if (mode & 1) != 0 {
+                        2 * self.samples_a[0] - self.samples_a[1]
+                    } else {
+                        (3 * self.samples_a[0] - self.samples_a[1]) >> 1
+                    };
+                self.samples_a[1] = self.samples_a[0];
+                (a, 0)
+            } else {
+                (self.samples_a[pos], (pos + mode as usize) & 7)
+            };
+        let l2 = l + ((i64::from(self.weight_a) * i64::from(a) + 512) >> 10) as i32;
+        if (a != 0) && (l != 0) {
+            self.weight_a -= ((((l ^ a) >> 30) & 2) - 1) * self.delta;
+        }
+        self.samples_a[npos] = l2;
+        l2
+    }
+    fn decorrelate_stereo(&mut self, l: i32, r: i32, pos: usize) -> (i32, i32) {
+        let mode = self.value;
+        if mode > 0 {
+            let (a, b, npos) = if mode > 8 {
+                    let (a, b) = if (mode & 1) != 0 {
+                            (2 * self.samples_a[0] - self.samples_a[1],
+                             2 * self.samples_b[0] - self.samples_b[1])
+                        } else {
+                            ((3 * self.samples_a[0] - self.samples_a[1]) >> 1,
+                             (3 * self.samples_b[0] - self.samples_b[1]) >> 1)
+                        };
+                    self.samples_a[1] = self.samples_a[0];
+                    self.samples_b[1] = self.samples_b[0];
+                    (a, b, 0)
+                } else {
+                    (self.samples_a[pos], self.samples_b[pos], (pos + mode as usize) & 7)
+                };
+            let l2 = l + ((i64::from(self.weight_a) * i64::from(a) + 512) >> 10) as i32;
+            let r2 = r + ((i64::from(self.weight_b) * i64::from(b) + 512) >> 10) as i32;
+            if (a != 0) && (l != 0) {
+                self.weight_a -= ((((l ^ a) >> 30) & 2) - 1) * self.delta;
+            }
+            if (b != 0) && (r != 0) {
+                self.weight_b -= ((((r ^ b) >> 30) & 2) - 1) * self.delta;
+            }
+            self.samples_a[npos] = l2;
+            self.samples_b[npos] = r2;
+            (l2, r2)
+        } else if mode == -1 {
+            let l2 = l + ((i64::from(self.weight_a) * i64::from(self.samples_a[0]) + 512) >> 10) as i32;
+            let r2 = r + ((i64::from(self.weight_b) * i64::from(l2) + 512) >> 10) as i32;
+            self.update_weight_a(self.samples_a[0], l);
+            self.update_weight_b(l2, r);
+            self.samples_a[0] = r2;
+            (l2, r2)
+        } else {
+            let r2 = r + ((i64::from(self.weight_b) * i64::from(self.samples_b[0]) + 512) >> 10) as i32;
+            self.update_weight_b(self.samples_b[0], r);
+            let rr = if mode == -3 {
+                    let nr = self.samples_a[0];
+                    self.samples_a[0] = r2;
+                    nr
+                } else {
+                    r2
+                };
+            let l2 = l + ((i64::from(self.weight_a) * i64::from(rr) + 512) >> 10) as i32;
+            self.update_weight_a(rr, l);
+            self.samples_b[0] = l2;
+            (l2, r2)
+        }
+    }
+    fn update_weight_a(&mut self, l: i32, r: i32) {
+        if (l != 0) && (r != 0) {
+            if (l ^ r) < 0 {
+                self.weight_a = (self.weight_a - self.delta).max(-1024)
+            } else {
+                self.weight_a = (self.weight_a + self.delta).min(1024)
+            }
+        }
+    }
+    fn update_weight_b(&mut self, l: i32, r: i32) {
+        if (l != 0) && (r != 0) {
+            if (l ^ r) < 0 {
+                self.weight_b = (self.weight_b - self.delta).max(-1024)
+            } else {
+                self.weight_b = (self.weight_b + self.delta).min(1024)
+            }
+        }
+    }
+}
+
+#[derive(Default)]
+struct DecState {
+    median:     [[u32; 3]; 2],
+    zero:       bool,
+    one:        bool,
+    num_zeroes: u32,
+    ebits:      u8,
+    shift:      u8,
+    and:        i32,
+    or:         i32,
+    post_shift: u8,
+    slow_level: [u32; 2],
+    br_acc:     [u32; 2],
+    br_delta:   [u32; 2],
+    hyb_max:    i32,
+    hyb_min:    i32,
+    has_hbr:    bool,
+    stereo:     bool,
+    error_lim:  [u32; 2],
+}
+
+fn read_biased_code(br: &mut BitReader) -> DecoderResult<u32> {
+    let val                             = br.read_code(UintCodeType::UnaryOnes)?;
+    validate!(val < 25);
+    if val < 2 {
+        Ok(val)
+    } else {
+        let bits = val - 1;
+        Ok((1 << bits) | br.read(bits as u8)?)
+    }
+}
+fn read_tail(br: &mut BitReader, bits: u32) -> DecoderResult<u32> {
+    if bits < 1 {
+        Ok(0)
+    } else {
+        let p = 31 - bits.leading_zeros();
+        let esc = (1 << (p + 1)) - (bits + 1);
+        let val                         = br.read(p as u8)?;
+        if val < esc {
+            Ok(val)
+        } else {
+            Ok(val * 2 - esc + br.read(1)?)
+        }
+    }
+}
+
+impl DecState {
+    fn read_sample(&mut self, br: &mut BitReader, channel: usize) -> DecoderResult<i32> {
+        if (self.median[0][0] < 2) && (self.median[1][0] < 2) && !self.zero && !self.one {
+            if self.num_zeroes > 0 {
+                self.num_zeroes -= 1;
+                if self.num_zeroes != 0 {
+                    return Ok(0);
+                }
+            } else {
+                self.num_zeroes = read_biased_code(br)?;
+                if self.num_zeroes != 0 {
+                    self.median = [[0; 3]; 2];
+                    return Ok(0);
+                }
+            }
+        }
+        let val = if self.zero {
+                self.zero = false;
+                0
+            } else {
+                let mut val             = br.read_code(UintCodeType::UnaryOnes)?;
+                validate!(val <= 16);
+                if val == 16 {
+                    val += read_biased_code(br)?;
+                }
+                let one = (val & 1) != 0;
+                val >>= 1;
+                if self.one {
+                    val += 1;
+                }
+                self.one = one;
+                self.zero = !one;
+                val
+            };
+
+        let (base, add) = match val {
+                0 => {
+                    let add = self.get_median(channel, 0) - 1;
+                    self.dec_median(channel, 0);
+                    (0, add)
+                },
+                1 => {
+                    let base = self.get_median(channel, 0);
+                    let add  = self.get_median(channel, 1) - 1;
+                    self.inc_median(channel, 0);
+                    self.dec_median(channel, 1);
+                    (base, add)
+                },
+                2 => {
+                    let base = self.get_median(channel, 0) + self.get_median(channel, 1);
+                    let add  = self.get_median(channel, 2) - 1;
+                    self.inc_median(channel, 0);
+                    self.inc_median(channel, 1);
+                    self.dec_median(channel, 2);
+                    (base, add)
+                },
+                _ => {
+                    let base = self.get_median(channel, 0) + self.get_median(channel, 1) + self.get_median(channel, 2) * (val - 2);
+                    let add  = self.get_median(channel, 2) - 1;
+                    self.inc_median(channel, 0);
+                    self.inc_median(channel, 1);
+                    self.inc_median(channel, 2);
+                    (base, add)
+                },
+            };
+        let val = base + read_tail(br, add)?;
+
+        if !br.read_bool()? {
+            Ok(val as i32)
+        } else {
+            Ok(!val as i32)
+        }
+    }
+    fn read_sample_hyb(&mut self, br: &mut BitReader, channel: usize) -> DecoderResult<i32> {
+        if (self.median[0][0] < 2) && (self.median[1][0] < 2) && !self.zero && !self.one {
+            if self.num_zeroes > 0 {
+                self.num_zeroes -= 1;
+                if self.num_zeroes != 0 {
+                    self.decay_slev(channel);
+                    return Ok(0);
+                }
+            } else {
+                self.num_zeroes = read_biased_code(br)?;
+                if self.num_zeroes != 0 {
+                    self.median = [[0; 3]; 2];
+                    self.decay_slev(channel);
+                    return Ok(0);
+                }
+            }
+        }
+        let val = if self.zero {
+                self.zero = false;
+                0
+            } else {
+                let mut val             = br.read_code(UintCodeType::UnaryOnes)?;
+                validate!(val <= 16);
+                if val == 16 {
+                    val += read_biased_code(br)?;
+                }
+                let one = (val & 1) != 0;
+                val >>= 1;
+                if self.one {
+                    val += 1;
+                }
+                self.one = one;
+                self.zero = !one;
+                val
+            };
+
+        if channel == 0 {
+            self.update_error_limit();
+        }
+
+        let (mut base, mut add) = match val {
+                0 => {
+                    let add = self.get_median(channel, 0) - 1;
+                    self.dec_median(channel, 0);
+                    (0, add)
+                },
+                1 => {
+                    let base = self.get_median(channel, 0);
+                    let add  = self.get_median(channel, 1) - 1;
+                    self.inc_median(channel, 0);
+                    self.dec_median(channel, 1);
+                    (base, add)
+                },
+                2 => {
+                    let base = self.get_median(channel, 0) + self.get_median(channel, 1);
+                    let add  = self.get_median(channel, 2) - 1;
+                    self.inc_median(channel, 0);
+                    self.inc_median(channel, 1);
+                    self.dec_median(channel, 2);
+                    (base, add)
+                },
+                _ => {
+                    let base = self.get_median(channel, 0) + self.get_median(channel, 1) + self.get_median(channel, 2) * (val - 2);
+                    let add  = self.get_median(channel, 2) - 1;
+                    self.inc_median(channel, 0);
+                    self.inc_median(channel, 1);
+                    self.inc_median(channel, 2);
+                    (base, add)
+                },
+            };
+        let val = if self.error_lim[channel] == 0 {
+                base + read_tail(br, add)?
+            } else {
+                let mut mid = (base * 2 + add + 1) >> 1;
+                while add > self.error_lim[channel] {
+                    if br.read_bool()? {
+                        add += base;
+                        add -= mid;
+                        base = mid;
+                    } else {
+                        add = mid - base - 1;
+                    }
+                    mid = (base * 2 + add + 1) >> 1;
+                }
+                mid
+            };
+
+        if self.has_hbr {
+            self.decay_slev(channel);
+            self.slow_level[channel] += wv_lin2log(val);
+        }
+
+        if !br.read_bool()? {
+            Ok(val as i32)
+        } else {
+            Ok(!val as i32)
+        }
+    }
+    fn decay_slev(&mut self, channel: usize) {
+        self.slow_level[channel] -= (self.slow_level[channel] + 0x80) >> 8;
+    }
+    fn update_error_limit(&mut self) {
+        let mut br = [0; 2];
+        let mut sl = [0; 2];
+
+        for i in 0..2 {
+            self.br_acc[i] += self.br_delta[i];
+            br[i] = self.br_acc[i] >> 16;
+            sl[i] = (self.slow_level[i] + 0x80) >> 8;
+        }
+
+        if self.stereo && self.has_hbr {
+            let balance = ((sl[1] as i32) - (sl[0] as i32) + (br[1] as i32) + 1) >> 1;
+            if balance > (br[0] as i32) {
+                br[1] = br[0] << 1;
+                br[0] = 0;
+            } else if -balance > (br[0] as i32) {
+                br[0] <<= 1;
+                br[1]   = 0;
+            } else {
+                br[1] = ((br[0] as i32) + balance) as u32;
+                br[0] = ((br[0] as i32) - balance) as u32;
+            }
+        }
+        for i in 0..2 {
+            self.error_lim[i] = if self.has_hbr {
+                    if sl[i] + 0x100 > br[i] {
+                        wv_log2lin((sl[i] + 0x100 - br[i]) as i32) as u32
+                    } else {
+                        0
+                    }
+                } else {
+                    wv_log2lin(br[i] as i32) as u32
+                };
+        }
+    }
+    fn get_median(&self, channel: usize, idx: usize) -> u32 {
+        (self.median[channel][idx] >> 4) + 1
+    }
+    fn inc_median(&mut self, channel: usize, idx: usize) {
+        self.median[channel][idx] += ((self.median[channel][idx] + (128 >> idx)) / (128 >> idx)) * 5;
+    }
+    fn dec_median(&mut self, channel: usize, idx: usize) {
+        self.median[channel][idx] -= ((self.median[channel][idx] + (128 >> idx) - 2) / (128 >> idx)) * 2;
+    }
+    fn produce_sample_common(&self, ebr: &mut BitReader, mut samp: i32) -> i32 {
+        if self.ebits > 0 {
+            samp <<= self.ebits;
+            if ebr.left() >= self.ebits as isize {
+                samp |=                 ebr.read(self.ebits).unwrap_or(0) as i32;
+            }
+        }
+        let bit = (samp & self.and) | self.or;
+        ((samp + bit) << self.shift) - bit
+    }
+    fn produce_sample(&self, ebr: &mut BitReader, samp: i32) -> i32 {
+        self.produce_sample_common(ebr, samp) << self.post_shift
+    }
+    fn produce_sample_hyb(&self, ebr: &mut BitReader, samp: i32) -> i32 {
+        self.produce_sample_common(ebr, samp).max(self.hyb_min).min(self.hyb_max) << self.post_shift
+    }
+}
+
+struct DecorrState {
+    decorr:     [Decorrelator; 16],
+    num_decorr: usize,
+}
+
+impl DecorrState {
+    fn new() -> Self {
+        Self {
+            decorr:     [Decorrelator::default(); 16],
+            num_decorr: 0,
+        }
+    }
+    fn reset(&mut self) {
+        self.decorr = [Decorrelator::default(); 16];
+        self.num_decorr = 0;
+    }
+}
+
+struct WavPackDecoder {
+    ainfo:      NAAudioInfo,
+    chmap:      NAChannelMap,
+    header:     WVHeader,
+
+    dstate:     DecorrState,
+}
+
+fn get_subblock(br: &mut ByteReader) -> DecoderResult<(u8, usize)> {
+    let id1                             = br.read_byte()?;
+    let id = id1 & 0x3F;
+    let mut len = 2 * if (id1 & 0x80) == 0 {
+                                          br.read_byte()? as usize
+        } else {
+                                          br.read_u24le()? as usize
+        };
+    if (id1 & 0x40) != 0 {
+        validate!(len > 0);
+        len -= 1;
+    }
+    Ok((id, len))
+}
+
+trait Output {
+    fn set(&mut self, val: i32);
+}
+
+impl Output for i16 {
+    fn set(&mut self, val: i32) { *self = val as i16; }
+}
+impl Output for i32 {
+    fn set(&mut self, val: i32) { *self = val; }
+}
+
+fn unpack_mono<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], len: usize) -> DecoderResult<u32> {
+    let mut crc = 0xFFFFFFFFu32;
+
+    for (i, dst) in dst[..len].iter_mut().enumerate() {
+        let mut l = state.read_sample(br, 0)?;
+        for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+            l = decorr.decorrelate_mono(l, i & 7);
+        }
+        crc = crc.wrapping_mul(3).wrapping_add(l as u32);
+        l = state.produce_sample(ebr, l);
+        dst.set(l);
+    }
+
+    Ok(crc)
+}
+
+#[allow(clippy::too_many_arguments)]
+fn unpack_stereo<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], off0: usize, off1: usize, len: usize, is_joint: bool) -> DecoderResult<u32> {
+    let mut crc = 0xFFFFFFFFu32;
+
+    for i in 0..len {
+        let mut l = state.read_sample(br, 0)?;
+        let mut r = state.read_sample(br, 1)?;
+        for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+            let (pl, pr) = decorr.decorrelate_stereo(l, r, i & 7);
+            l = pl;
+            r = pr;
+        }
+        if is_joint {
+            r -= l >> 1;
+            l += r;
+        }
+        crc = crc.wrapping_mul(3).wrapping_add(l as u32).wrapping_mul(3).wrapping_add(r as u32);
+        l = state.produce_sample(ebr, l);
+        r = state.produce_sample(ebr, r);
+        dst[off0 + i].set(l);
+        dst[off1 + i].set(r);
+    }
+
+    Ok(crc)
+}
+
+fn unpack_mono_hyb<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], len: usize) -> DecoderResult<u32> {
+    let mut crc = 0xFFFFFFFFu32;
+
+    for (i, dst) in dst[..len].iter_mut().enumerate() {
+        let mut l = state.read_sample_hyb(br, 0)?;
+        for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+            l = decorr.decorrelate_mono(l, i & 7);
+        }
+        crc = crc.wrapping_mul(3).wrapping_add(l as u32);
+        l = state.produce_sample_hyb(ebr, l);
+        dst.set(l);
+    }
+
+    Ok(crc)
+}
+
+#[allow(clippy::too_many_arguments)]
+fn unpack_stereo_hyb<T: Output+Copy>(br: &mut BitReader, ebr: &mut BitReader, state: &mut DecState, decorr: &mut DecorrState, dst: &mut [T], off0: usize, off1: usize, len: usize, is_joint: bool) -> DecoderResult<u32> {
+    let mut crc = 0xFFFFFFFFu32;
+
+    for i in 0..len {
+        let mut l = state.read_sample_hyb(br, 0)?;
+        let mut r = state.read_sample_hyb(br, 1)?;
+        for decorr in decorr.decorr[..decorr.num_decorr].iter_mut() {
+            let (pl, pr) = decorr.decorrelate_stereo(l, r, i & 7);
+            l = pl;
+            r = pr;
+        }
+        if is_joint {
+            r -= l >> 1;
+            l += r;
+        }
+        crc = crc.wrapping_mul(3).wrapping_add(l as u32).wrapping_mul(3).wrapping_add(r as u32);
+        l = state.produce_sample_hyb(ebr, l);
+        r = state.produce_sample_hyb(ebr, r);
+        dst[off0 + i].set(l);
+        dst[off1 + i].set(r);
+    }
+
+    Ok(crc)
+}
+
+impl WavPackDecoder {
+    fn new() -> Self {
+        Self {
+            ainfo:      NAAudioInfo::new(0, 1, SND_S16P_FORMAT, 0),
+            chmap:      NAChannelMap::new(),
+            header:     WVHeader::default(),
+
+            dstate:     DecorrState::new(),
+        }
+    }
+    #[allow(clippy::cyclomatic_complexity)]
+    fn decode_block(&mut self, hdr: &WVHeader, src: &[u8], start_ch: usize, abuf: &mut NABufferType) -> DecoderResult<()> {
+        let mut mr = MemoryReader::new_read(src);
+        let mut br = ByteReader::new(&mut mr);
+        let mut has_terms = false;
+        let mut has_weights = false;
+        let mut has_samples = false;
+        let mut has_hybrid = false;
+        let is_mono = (hdr.flags & (WV_FLAG_MONO | WV_FLAG_FALSE_STEREO)) != 0;
+        let cur_channels = if is_mono { 1 } else { 2 };
+        let mut data_pos = 0;
+        let mut data_len = 0;
+        let mut ebits_pos = 0;
+        let mut ebits_len = 0;
+        let mut dec_state = DecState::default();
+        self.dstate.reset();
+        dec_state.post_shift = if (hdr.get_bits() & 8) != 0 { 8 } else { 0 };
+        dec_state.post_shift += ((hdr.flags >> 13) & 0x1F) as u8;
+        validate!(dec_state.post_shift < 32);
+        dec_state.hyb_max = 0x7FFFFFFF >> (32 - hdr.get_bits());
+        dec_state.hyb_min = -dec_state.hyb_max - 1;
+        let is_hybrid = (hdr.flags & WV_FLAG_HYBRID) != 0;
+        let has_hybrid_br = (hdr.flags & WV_FLAG_HYB_BITRATE) != 0;
+        dec_state.has_hbr = has_hybrid_br;
+        dec_state.stereo  = !is_mono;
+        while br.left() > 0 {
+            let (id, len) = get_subblock(&mut br)?;
+            match id {
+                0x02 => { //decorr terms
+                    self.dstate.num_decorr = len;
+                    validate!(self.dstate.num_decorr <= self.dstate.decorr.len());
+                    for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev() {
+                        let val         = br.read_byte()?;
+                        decorr.value = i32::from(val & 0x1F) - 5;
+                        decorr.delta = i32::from(val >> 5);
+                    }
+                    has_terms = true;
+                },
+                0x03 => { //decorr weights
+                    validate!(has_terms);
+                    validate!(len <= self.dstate.num_decorr * cur_channels);
+                    for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev().take(len / cur_channels) {
+                        let val         = br.read_byte()? as i8;
+                        decorr.weight_a = i32::from(val) << 3;
+                        if decorr.weight_a > 0 {
+                            decorr.weight_a += (decorr.weight_a + 64) >> 7;
+                        }
+                        if !is_mono {
+                            let val     = br.read_byte()? as i8;
+                            decorr.weight_b = i32::from(val) << 3;
+                            if decorr.weight_b > 0 {
+                                decorr.weight_b += (decorr.weight_b + 64) >> 7;
+                            }
+                        }
+                    }
+                    has_weights = true;
+                },
+                0x04 => { //decorr samples
+                    validate!(has_weights);
+                    let end = br.tell() + (len as u64);
+                    for decorr in self.dstate.decorr[..self.dstate.num_decorr].iter_mut().rev() {
+                        if br.tell() == end {
+                            break;
+                        }
+                        if decorr.value > 8 {
+                            let a0      = br.read_u16le()? as i16;
+                            let a1      = br.read_u16le()? as i16;
+                            decorr.samples_a[0] = wv_log2lin(i32::from(a0));
+                            decorr.samples_a[1] = wv_log2lin(i32::from(a1));
+                            if !is_mono {
+                                let b0  = br.read_u16le()? as i16;
+                                let b1  = br.read_u16le()? as i16;
+                                decorr.samples_b[0] = wv_log2lin(i32::from(b0));
+                                decorr.samples_b[1] = wv_log2lin(i32::from(b1));
+                            }
+                        } else if decorr.value < 0 {
+                            let a0      = br.read_u16le()? as i16;
+                            let b0      = br.read_u16le()? as i16;
+                            decorr.samples_a[0] = wv_log2lin(i32::from(a0));
+                            decorr.samples_b[0] = wv_log2lin(i32::from(b0));
+                        } else {
+                            let len = decorr.value as usize;
+                            for i in 0..len {
+                                let a   = br.read_u16le()? as i16;
+                                decorr.samples_a[i] = wv_log2lin(i32::from(a));
+                                if !is_mono {
+                                    let b = br.read_u16le()? as i16;
+                                    decorr.samples_b[i] = wv_log2lin(i32::from(b));
+                                }
+                            }
+                        }
+                    }
+                    has_samples = true;
+                },
+                0x05 => { //entropy vars
+                    validate!(len == 6 * cur_channels);
+                    for el in dec_state.median[0].iter_mut() {
+                        *el             = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+                    }
+                    if !is_mono {
+                        for el in dec_state.median[1].iter_mut() {
+                            *el         = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+                        }
+                    }
+                },
+                0x06 => { //hybrid parameters
+                    validate!(is_hybrid);
+                    let end = br.tell() + (len as u64);
+                    if has_hybrid_br {
+                        for el in dec_state.slow_level.iter_mut().take(cur_channels) {
+                            *el         = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+                        }
+                    }
+                    for el in dec_state.br_acc.iter_mut().take(cur_channels) {
+                        *el             = u32::from(br.read_u16le()?) << 16;
+                    }
+                    if br.tell() < end {
+                        for el in dec_state.br_delta.iter_mut().take(cur_channels) {
+                            *el         = wv_log2lin(i32::from(br.read_u16le()? as i16)) as u32;
+                        }
+                    }
+                    validate!(br.tell() == end);
+                    has_hybrid = true;
+                },
+                0x08 => {
+                    validate!((hdr.flags & WV_FLAG_FLOATS) != 0);
+                    return Err(DecoderError::NotImplemented);
+                },
+                0x09 => {
+                    validate!((hdr.flags & WV_FLAG_EXT_INTEGERS) != 0);
+                    validate!(len == 4);
+                    let ebits           = br.read_byte()?;
+                    let mode1           = br.read_byte()?;
+                    let mode2           = br.read_byte()?;
+                    let mode3           = br.read_byte()?;
+                    if ebits != 0 {
+                        dec_state.ebits = ebits;
+                    } else if mode1 != 0 {
+                        dec_state.shift = mode1;
+                    } else if mode2 != 0 {
+                        dec_state.and = 1;
+                        dec_state.or  = 1;
+                        dec_state.shift = mode2;
+                    } else if mode3 != 0 {
+                        dec_state.and = 1;
+                        dec_state.shift = mode3;
+                    }
+                    if is_hybrid && hdr.get_bits() == 32 && dec_state.post_shift < 8 && dec_state.shift > 8 {
+                        dec_state.post_shift    += 8;
+                        dec_state.shift         -= 8;
+                        dec_state.hyb_min       >>= 8;
+                        dec_state.hyb_max       >>= 8;
+                    }
+                },
+                0x0A => { // normal stream
+                    validate!(has_samples);
+                    data_pos = br.tell() as usize;
+                    data_len = len;
+                    br.read_skip(len)?;
+                },
+                0x0C => {
+                    ebits_pos = br.tell() as usize;
+                    ebits_len = len;
+                    br.read_skip(len)?;
+                },
+                0x0E => return Err(DecoderError::NotImplemented), // DSD
+                _ => { br.read_skip(len)?; },
+            };
+            if (len & 1) != 0 {
+                                        br.read_skip(1)?;
+            }
+        }
+        validate!(data_pos > 0 && data_len > 0);
+        if is_hybrid {
+            validate!(has_hybrid);
+        }
+
+        let mut br = BitReader::new(&src[data_pos..][..data_len], BitReaderMode::LE);
+        let mut ebr = BitReader::new(&src[ebits_pos..][..ebits_len], BitReaderMode::LE);
+        if is_mono {
+            let is_fstereo = (hdr.flags & WV_FLAG_FALSE_STEREO) != 0;
+            match abuf {
+                NABufferType::AudioI16(ref mut adata) => {
+                    let off0 = adata.get_offset(start_ch);
+                    let off1 = adata.get_offset(start_ch + 1);
+                    let dst = adata.get_data_mut().unwrap();
+                    let crc = if !is_hybrid {
+                            unpack_mono(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+                        } else {
+                            unpack_mono_hyb(&mut br, &mut ebr, &mut dec_state, &mut
+ self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+                        };
+                    if crc != hdr.crc {
+                        return Err(DecoderError::ChecksumError);
+                    }
+                    if is_fstereo {
+                        for i in 0..(hdr.block_samples as usize) {
+                            dst[off1 + i] = dst[off0 + i];
+                        }
+                    }
+                },
+                NABufferType::AudioI32(ref mut adata) => {
+                    let off0 = adata.get_offset(start_ch);
+                    let off1 = adata.get_offset(start_ch + 1);
+                    let dst = adata.get_data_mut().unwrap();
+                    let crc = if !is_hybrid {
+                            unpack_mono(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+                        } else {
+                            unpack_mono_hyb(&mut br, &mut ebr, &mut dec_state, &mut
+ self.dstate, &mut dst[off0..], hdr.block_samples as usize)?
+                        };
+                    if crc != hdr.crc {
+                        return Err(DecoderError::ChecksumError);
+                    }
+                    if is_fstereo {
+                        for i in 0..(hdr.block_samples as usize) {
+                            dst[off1 + i] = dst[off0 + i];
+                        }
+                    }
+                },
+                _ => unreachable!(),
+            }
+        } else {
+            let is_joint = (hdr.flags & WV_FLAG_JSTEREO) != 0;
+            match abuf {
+                NABufferType::AudioI16(ref mut adata) => {
+                    let off0 = adata.get_offset(start_ch);
+                    let off1 = adata.get_offset(start_ch + 1);
+                    let dst = adata.get_data_mut().unwrap();
+                    let crc = if !is_hybrid {
+                            unpack_stereo(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+                        } else {
+                            unpack_stereo_hyb(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+                        };
+                    if crc != hdr.crc {
+                        return Err(DecoderError::ChecksumError);
+                    }
+                },
+                NABufferType::AudioI32(ref mut adata) => {
+                    let off0 = adata.get_offset(start_ch);
+                    let off1 = adata.get_offset(start_ch + 1);
+                    let dst = adata.get_data_mut().unwrap();
+                    let crc = if !is_hybrid {
+                            unpack_stereo(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+                        } else {
+                            unpack_stereo_hyb(&mut br, &mut ebr, &mut dec_state, &mut self.dstate, dst, off0, off1, hdr.block_samples as usize, is_joint)?
+                        };
+                    if crc != hdr.crc {
+                        return Err(DecoderError::ChecksumError);
+                    }
+                },
+                _ => unreachable!(),
+            }
+        }
+
+        Ok(())
+    }
+}
+
+impl NADecoder for WavPackDecoder {
+    fn init(&mut self, _supp: &mut NADecoderSupport, info: NACodecInfoRef) -> DecoderResult<()> {
+        if let NACodecTypeInfo::Audio(_ainfo) = info.get_properties() {
+            if let Some(buf) = info.get_extradata() {
+                let mut channels = 0;
+                let mut decl_channels = 0;
+                let mut channel_map = 0;
+                let mut off = 0;
+                while off < buf.len() {
+                    let hdr = WVHeader::parse(&buf[off..])?;
+                    if (hdr.flags & (WV_FLAG_FLOATS | WV_FLAG_DSD_AUDIO)) != 0 {
+                        return Err(DecoderError::NotImplemented);
+                    }
+                    self.header = hdr;
+                    off += WV_HEADER_SIZE;
+                    let size = hdr.get_size();
+                    let mut mr = MemoryReader::new_read(&buf[off..][..size]);
+                    let mut br = ByteReader::new(&mut mr);
+                    while br.left() > 0 {
+                        let (id, len)   = get_subblock(&mut br)?;
+                        match id {
+                            0xD => {
+                                validate!(len > 1);
+                                decl_channels = br.read_byte()?;
+                                if decl_channels == 0 {
+                                    return Err(DecoderError::NotImplemented);
+                                }
+                                channel_map = match len {
+                                        2 => u32::from(br.read_byte()?),
+                                        3 => u32::from(br.read_u16le()?),
+                                        4 => br.read_u24le()?,
+                                        5 => br.read_u32le()?,
+                                        _ => return Err(DecoderError::NotImplemented),
+                                    };
+                            },
+                            _ =>          br.read_skip(len)?,
+                        };
+                        if (len & 1) != 0 {
+                                          br.read_skip(1)?;
+                        }
+                    }
+                    channels += hdr.get_num_channels();
+
+                    if hdr.is_end_block() {
+                        break;
+                    }
+                    off += size;
+                }
+                if decl_channels != 0 {
+                    validate!(decl_channels == channels);
+                }
+                self.chmap = if channel_map != 0 {
+                        NAChannelMap::from_ms_mapping(channel_map)
+                    } else if channels == 1 {
+                        NAChannelMap::from_str("C").unwrap()
+                    } else if channels == 2 {
+                        NAChannelMap::from_str("L,R").unwrap()
+                    } else {
+                        return Err(DecoderError::NotImplemented);
+                    };
+                let bsamps = if self.header.block_samples == 0 {
+                        self.header.get_sample_rate()
+                    } else {
+                        self.header.block_samples
+                    } as usize;
+
+                let bits = self.header.get_bits();
+                let fmt = if (self.header.flags & WV_FLAG_FLOATS) != 0 {
+                        SND_F32P_FORMAT
+                    } else if bits <= 16 {
+                        SND_S16P_FORMAT
+                    } else {
+                        SND_S32P_FORMAT
+                    };
+
+                self.ainfo = NAAudioInfo::new(self.header.get_sample_rate(), channels, fmt, bsamps);
+                Ok(())
+            } else {
+                Err(DecoderError::InvalidData)
+            }
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn decode(&mut self, _supp: &mut NADecoderSupport, pkt: &NAPacket) -> DecoderResult<NAFrameRef> {
+        let info = pkt.get_stream().get_info();
+        if let NACodecTypeInfo::Audio(_) = info.get_properties() {
+            let pktbuf = pkt.get_buffer();
+            validate!(pktbuf.len() > WV_HEADER_SIZE);
+            let refhdr = WVHeader::parse(&pktbuf)?;
+
+            if refhdr.block_samples == 0 {
+                let mut frm = NAFrame::new_from_pkt(pkt, info, NABufferType::None);
+                frm.set_frame_type(FrameType::Skip);
+                frm.set_keyframe(false);
+                return Ok(frm.into_ref());
+            }
+
+            let mut abuf = alloc_audio_buffer(self.ainfo, refhdr.block_samples as usize, self.chmap.clone())?;
+            let mut start_ch = 0;
+            let mut roff = 0;
+            let mut first = true;
+            let mut refhdr = WVHeader::default();
+            loop {
+                let hdr = WVHeader::parse(&pktbuf[roff..])?;
+                if first {
+                    validate!(hdr.is_start_block());
+                    validate!(self.header.stream_eq(&hdr));
+                    refhdr = hdr;
+                    first = false;
+                } else {
+                    validate!(refhdr.block_eq(&hdr));
+                }
+                roff += WV_HEADER_SIZE;
+                let blk_size = hdr.get_size();
+                self.decode_block(&hdr, &pktbuf[roff..][..blk_size], start_ch, &mut abuf)?;
+                roff += blk_size;
+                if hdr.is_end_block() {
+                    break;
+                }
+                start_ch += hdr.get_num_channels() as usize;
+            }
+            let mut frm = NAFrame::new_from_pkt(pkt, info, abuf);
+            frm.set_duration(Some(u64::from(refhdr.block_samples)));
+            Ok(frm.into_ref())
+        } else {
+            Err(DecoderError::InvalidData)
+        }
+    }
+    fn flush(&mut self) {
+    }
+}
+
+impl NAOptionHandler for WavPackDecoder {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub fn get_decoder() -> Box<dyn NADecoder + Send> {
+    Box::new(WavPackDecoder::new())
+}
+
+#[cfg(test)]
+mod test {
+    use nihav_core::codecs::RegisteredDecoders;
+    use nihav_core::demuxers::RegisteredDemuxers;
+    use nihav_codec_support::test::dec_video::*;
+    use crate::llaudio_register_all_decoders;
+    use crate::llaudio_register_all_demuxers;
+    #[test]
+    fn test_wavpack_8bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/8bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x8157bf0f, 0xeb441905, 0xeb6b815d, 0x113480a8]));
+    }
+    #[test]
+    fn test_wavpack_12bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/12bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xe5faf18c, 0xbf2d3b12, 0x5b0b8f00, 0x162b805a]));
+    }
+    #[test]
+    fn test_wavpack_16bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/16bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xaf31b252, 0xdf8b282a, 0x2dc38947, 0xf64c68a1]));
+    }
+    #[test]
+    fn test_wavpack_24bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/24bit-partial.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0xf5649972, 0xfe757241, 0x383d5ded, 0x0176a75b]));
+    }
+    #[test]
+    fn test_wavpack_hybrid() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/4.0_16-bit.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x9cfa469a, 0x54af50e1, 0xe45434d1, 0x1bf987e2]));
+    }
+    #[test]
+    fn test_wavpack_hybrid_32bit() {
+        let mut dmx_reg = RegisteredDemuxers::new();
+        llaudio_register_all_demuxers(&mut dmx_reg);
+        let mut dec_reg = RegisteredDecoders::new();
+        llaudio_register_all_decoders(&mut dec_reg);
+
+        test_decoding("wavpack", "wavpack", "assets/LLaudio/wv/4.0_32-bit_int.wv", Some(100000), &dmx_reg, &dec_reg,
+                      ExpectedTestResult::MD5([0x21415549, 0xf48ddb55, 0xef5c4e7f, 0xa48d5ab9]));
+    }
+}
+
+const WV_EXP_TABLE: [u8; 256] = [
+    0x00, 0x01, 0x01, 0x02, 0x03, 0x03, 0x04, 0x05,
+    0x06, 0x06, 0x07, 0x08, 0x08, 0x09, 0x0a, 0x0b,
+    0x0b, 0x0c, 0x0d, 0x0e, 0x0e, 0x0f, 0x10, 0x10,
+    0x11, 0x12, 0x13, 0x13, 0x14, 0x15, 0x16, 0x16,
+    0x17, 0x18, 0x19, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
+    0x1d, 0x1e, 0x1f, 0x20, 0x20, 0x21, 0x22, 0x23,
+    0x24, 0x24, 0x25, 0x26, 0x27, 0x28, 0x28, 0x29,
+    0x2a, 0x2b, 0x2c, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+    0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x35, 0x36,
+    0x37, 0x38, 0x39, 0x3a, 0x3a, 0x3b, 0x3c, 0x3d,
+    0x3e, 0x3f, 0x40, 0x41, 0x41, 0x42, 0x43, 0x44,
+    0x45, 0x46, 0x47, 0x48, 0x48, 0x49, 0x4a, 0x4b,
+    0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x51, 0x52,
+    0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+    0x5b, 0x5c, 0x5d, 0x5e, 0x5e, 0x5f, 0x60, 0x61,
+    0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+    0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71,
+    0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+    0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81,
+    0x82, 0x83, 0x84, 0x85, 0x87, 0x88, 0x89, 0x8a,
+    0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92,
+    0x93, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
+    0x9c, 0x9d, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+    0xa5, 0xa6, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad,
+    0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb6, 0xb7,
+    0xb8, 0xb9, 0xba, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0,
+    0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc8, 0xc9, 0xca,
+    0xcb, 0xcd, 0xce, 0xcf, 0xd0, 0xd2, 0xd3, 0xd4,
+    0xd6, 0xd7, 0xd8, 0xd9, 0xdb, 0xdc, 0xdd, 0xde,
+    0xe0, 0xe1, 0xe2, 0xe4, 0xe5, 0xe6, 0xe8, 0xe9,
+    0xea, 0xec, 0xed, 0xee, 0xf0, 0xf1, 0xf2, 0xf4,
+    0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfc, 0xfd, 0xff
+];
+const WV_LOG_TABLE: [u8; 256] = [
+    0x00, 0x01, 0x03, 0x04, 0x06, 0x07, 0x09, 0x0a,
+    0x0b, 0x0d, 0x0e, 0x10, 0x11, 0x12, 0x14, 0x15,
+    0x16, 0x18, 0x19, 0x1a, 0x1c, 0x1d, 0x1e, 0x20,
+    0x21, 0x22, 0x24, 0x25, 0x26, 0x28, 0x29, 0x2a,
+    0x2c, 0x2d, 0x2e, 0x2f, 0x31, 0x32, 0x33, 0x34,
+    0x36, 0x37, 0x38, 0x39, 0x3b, 0x3c, 0x3d, 0x3e,
+    0x3f, 0x41, 0x42, 0x43, 0x44, 0x45, 0x47, 0x48,
+    0x49, 0x4a, 0x4b, 0x4d, 0x4e, 0x4f, 0x50, 0x51,
+    0x52, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a,
+    0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63,
+    0x64, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c,
+    0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x74, 0x75,
+    0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d,
+    0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85,
+    0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d,
+    0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95,
+    0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9b, 0x9c,
+    0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4,
+    0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xa9, 0xaa, 0xab,
+    0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb2,
+    0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xb9,
+    0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc0,
+    0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc6, 0xc7,
+    0xc8, 0xc9, 0xca, 0xcb, 0xcb, 0xcc, 0xcd, 0xce,
+    0xcf, 0xd0, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd4,
+    0xd5, 0xd6, 0xd7, 0xd8, 0xd8, 0xd9, 0xda, 0xdb,
+    0xdc, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe0, 0xe1,
+    0xe2, 0xe3, 0xe4, 0xe4, 0xe5, 0xe6, 0xe7, 0xe7,
+    0xe8, 0xe9, 0xea, 0xea, 0xeb, 0xec, 0xed, 0xee,
+    0xee, 0xef, 0xf0, 0xf1, 0xf1, 0xf2, 0xf3, 0xf4,
+    0xf4, 0xf5, 0xf6, 0xf7, 0xf7, 0xf8, 0xf9, 0xf9,
+    0xfa, 0xfb, 0xfc, 0xfc, 0xfd, 0xfe, 0xff, 0xff
+];
diff --git a/nihav-llaudio/src/demuxers/ape.rs b/nihav-llaudio/src/demuxers/ape.rs
new file mode 100644 (file)
index 0000000..2969c78
--- /dev/null
@@ -0,0 +1,267 @@
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+#[derive(Clone,Copy)]
+struct Frame {
+    off:            u32,
+    size:           u32,
+    bits_off:       u8,
+}
+
+struct APEDemuxer<'a> {
+    src:            &'a mut ByteReader<'a>,
+    cur_frame:      usize,
+    frames:         Vec<Frame>,
+    normal_blocks:  u32,
+    last_blocks:    u32,
+    truncated:      bool,
+}
+
+impl<'a> APEDemuxer<'a> {
+    fn new(io: &'a mut ByteReader<'a>) -> Self {
+        Self {
+            src:            io,
+            cur_frame:      0,
+            frames:         Vec::new(),
+            normal_blocks:  0,
+            last_blocks:    0,
+            truncated:      false,
+        }
+    }
+}
+
+impl<'a> DemuxCore<'a> for APEDemuxer<'a> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+        let src = &mut self.src;
+
+        let tag                         = src.read_tag()?;
+        validate!(&tag == b"MAC ");
+        let version                     = src.read_u16le()?;
+        validate!(version >= 3800 && version <= 3990);
+
+        let seektab_len;
+        let _wavtail_len;
+        let compr_type;
+        let flags;
+        let blocksperframe;
+        let finalblocks;
+        let nframes;
+        let bits;
+        let channels;
+        let srate;
+        if version >= 3980 {
+                                          src.read_skip(2)?;
+            let descriptor_len          = src.read_u32le()? as usize;
+            let header_len              = src.read_u32le()? as usize;
+            validate!(header_len == 24);
+            seektab_len                 = src.read_u32le()? as usize;
+            let _wavheader_len          = src.read_u32le()? as usize;
+            let _audio_len              = src.read_u64le()?;
+            _wavtail_len                = src.read_u32le()? as usize;
+                                          src.read_skip(16)?; // unpacked data MD5
+            if descriptor_len > 52 {
+                                          src.read_skip(descriptor_len - 52)?;
+            }
+
+            compr_type                  = src.read_u16le()?;
+            flags                       = src.read_u16le()?;
+            blocksperframe              = src.read_u32le()?;
+            finalblocks                 = src.read_u32le()?;
+            nframes                     = src.read_u32le()? as usize;
+            bits                        = src.read_u16le()?;
+            channels                    = src.read_u16le()?;
+            srate                       = src.read_u32le()?;
+        } else {
+            compr_type                  = src.read_u16le()?;
+            flags                       = src.read_u16le()?;
+            channels                    = src.read_u16le()?;
+            srate                       = src.read_u32le()?;
+
+            let wavheader_len           = src.read_u32le()? as usize;
+            _wavtail_len                = src.read_u32le()? as usize;
+            nframes                     = src.read_u32le()? as usize;
+            finalblocks                 = src.read_u32le()?;
+            if (flags & 0x04) != 0 {
+                                          src.read_u32le()?; // peak level
+            }
+            if (flags & 0x10) != 0 {
+                seektab_len             = src.read_u32le()? as usize * 4;
+            } else {
+                seektab_len = nframes * 4;
+            }
+
+            if (flags & 0x01) != 0 {
+                bits = 8;
+            } else if (flags & 0x08) != 0 {
+                bits = 24;
+            } else {
+                bits = 16;
+            }
+
+            blocksperframe = 9216 * if version >= 3950 {
+                    32
+                } else if (version >= 3900) || ((version >= 3800) && (compr_type >= 4000)) {
+                    8
+                } else {
+                    1
+                };
+
+            if (flags & 0x20) == 0 {
+                                          src.read_skip(wavheader_len)?;
+            }
+        }
+        validate!(srate > 0);
+        validate!(channels > 0 && channels < 256);
+        validate!(bits > 0 && bits <= 32);
+        validate!(nframes > 0 && nframes < (1 << 28));
+        validate!(seektab_len == nframes * 4);
+
+        self.frames = Vec::with_capacity(nframes);
+        self.normal_blocks = blocksperframe;
+        self.last_blocks   = finalblocks;
+
+        seek_index.mode = SeekIndexMode::Present;
+        let first_off                   = src.peek_u32le()?;
+        validate!(u64::from(first_off) >= src.tell() + ((nframes * 4) as u64));
+        let mut last_off = first_off - 1;
+        for i in 0..nframes {
+            let off                     = src.read_u32le()?;
+            validate!(off > last_off);
+            let diff = (off - first_off) & 3;
+            self.frames.push(Frame {
+                    off:        off - diff,
+                    size:       0,
+                    bits_off:   (diff as u8) * 8,
+                });
+
+            last_off = off;
+
+            let time = (i as u64) * u64::from(blocksperframe) * 1000 / u64::from(srate);
+            seek_index.add_entry(0, SeekEntry { time, pts: i as u64, pos: i as u64 });
+        }
+        if version < 3810 {
+            for frame in self.frames.iter_mut() {
+                let bits                = src.read_byte()?;
+                validate!(bits < 32);
+                frame.bits_off += bits;
+            }
+        }
+                                          src.seek(SeekFrom::End(0))?;
+        let fsize = src.tell();
+        validate!(fsize > u64::from(self.frames[0].off));
+        self.truncated = u64::from(self.frames[self.frames.len() - 1].off) >= fsize;
+        if self.truncated {
+            let mut valid_frames = self.frames.len();
+            for frame in self.frames.iter_mut().rev() {
+                if u64::from(frame.off) >= fsize {
+                    valid_frames -= 1;
+                }
+            }
+            self.frames.truncate(valid_frames);
+            validate!(!self.frames.is_empty());
+            self.truncated = true;
+        }
+        let mut last_off = fsize as u32;
+        for frame in self.frames.iter_mut().rev() {
+            frame.size = last_off - frame.off;
+            last_off = frame.off + (if frame.bits_off > 0 { 4 } else { 0 });
+        }
+
+        let mut hdr = vec![0u8; 16];
+        write_u16le(&mut hdr[0..], version)?;
+        write_u16le(&mut hdr[2..], compr_type)?;
+        write_u16le(&mut hdr[4..], flags)?;
+        hdr[6] = channels as u8;
+        hdr[7] = bits as u8;
+        write_u32le(&mut hdr[8..], srate)?;
+        write_u32le(&mut hdr[12..], blocksperframe)?;
+
+        let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 1);
+        let ainfo = NACodecInfo::new("ape", NACodecTypeInfo::Audio(ahdr), Some(hdr));
+        strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, blocksperframe, srate)).unwrap();
+
+        self.cur_frame = 0;
+
+        Ok(())
+    }
+    fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+        if self.cur_frame >= self.frames.len() {
+            return Err(DemuxerError::EOF);
+        }
+
+        let size = self.frames[self.cur_frame].size as usize;
+        let off  = self.frames[self.cur_frame].off;
+        let bits = self.frames[self.cur_frame].bits_off;
+        let nblocks = if (self.cur_frame < self.frames.len() - 1) || self.truncated { self.normal_blocks } else { self.last_blocks };
+
+                                          self.src.seek(SeekFrom::Start(off.into()))?;
+
+        let mut buf = vec![0u8; size + 8];
+        write_u32le(&mut buf[0..], nblocks)?;
+        buf[4] = bits;
+                                          self.src.read_buf(&mut buf[8..])?;
+
+        let stream = strmgr.get_stream(0).unwrap();
+        let (tb_num, tb_den) = stream.get_timebase();
+        let ts = NATimeInfo::new(Some(self.cur_frame as u64), None, None, tb_num, tb_den);
+        let pkt = NAPacket::new(stream, ts, true, buf);
+
+        self.cur_frame += 1;
+
+        Ok(pkt)
+    }
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        let ret = seek_index.find_pos(time);
+        if ret.is_none() {
+            return Err(DemuxerError::SeekError);
+        }
+        let seek_info = ret.unwrap();
+        self.cur_frame = seek_info.pts as usize;
+        if self.cur_frame >= self.frames.len() {
+            return Err(DemuxerError::SeekError);
+        }
+
+        Ok(())
+    }
+}
+
+impl<'a> NAOptionHandler for APEDemuxer<'a> {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct APEDemuxerCreator { }
+
+impl DemuxerCreator for APEDemuxerCreator {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+        Box::new(APEDemuxer::new(br))
+    }
+    fn get_name(&self) -> &'static str { "ape" }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+
+    #[test]
+    fn test_ape_demux() {
+        let mut file = File::open("assets/LLaudio/ape/luckynight.ape").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = APEDemuxer::new(&mut br);
+        let mut sm = StreamManager::new();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
+        loop {
+            let pktres = dmx.get_frame(&mut sm);
+            if let Err(e) = pktres {
+                if (e as i32) == (DemuxerError::EOF as i32) { break; }
+                panic!("error");
+            }
+            let pkt = pktres.unwrap();
+            println!("Got {}", pkt);
+        }
+    }
+}
diff --git a/nihav-llaudio/src/demuxers/flac.rs b/nihav-llaudio/src/demuxers/flac.rs
new file mode 100644 (file)
index 0000000..f19ce56
--- /dev/null
@@ -0,0 +1,242 @@
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+struct FLACDemuxer<'a> {
+    src:            &'a mut ByteReader<'a>,
+    data_start:     u64,
+    tot_samples:    u64,
+    cur_samples:    u64,
+    blk_samples:    u16,
+    min_size:       usize,
+    max_size:       usize,
+}
+
+impl<'a> FLACDemuxer<'a> {
+    fn new(io: &'a mut ByteReader<'a>) -> Self {
+        Self {
+            src:            io,
+            data_start:     0,
+            tot_samples:    0,
+            cur_samples:    0,
+            blk_samples:    0,
+            min_size:       0,
+            max_size:       0,
+        }
+    }
+}
+
+fn update_crc16(crc: u16, byte: u8) -> u16 {
+    (crc << 8) ^ CRC16_TABLE[(((crc >> 8) as u8) ^ byte) as usize]
+}
+
+fn read_utf8(src: &[u8]) -> DemuxerResult<u32> {
+    if (src[0] & 0x80) == 0 {
+        return Ok(u32::from(src[0]));
+    }
+    let len = (!src[0]).leading_zeros() as usize;
+    validate!(len != 1 && len <= 5 && src.len() >= len);
+    let mut val = u32::from(src[0] & 0x1F);
+    for byte in src.iter().take(len).skip(1) {
+        validate!((*byte & 0xC0) == 0x80);
+        val = (val << 6) | u32::from(*byte & 0x3F);
+    }
+    Ok(val)
+}
+
+impl<'a> DemuxCore<'a> for FLACDemuxer<'a> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+        let tag                         = self.src.read_tag()?;
+        validate!(&tag == b"fLaC");
+        let mut streaminfo: Vec<u8> = Vec::new();
+        let mut srate = 0u32;
+        let mut channels = 0u8;
+        loop {
+            let id1                     = self.src.read_byte()?;
+            let len                     = self.src.read_u24be()? as usize;
+            let id = id1 & 0x7F;
+
+            match id {
+                0x00 => {
+                    validate!(len >= 34);
+                    streaminfo = vec![0u8; len];
+                                          self.src.read_buf(&mut streaminfo)?;
+                    let min_bs          = read_u16be(&streaminfo[0..])?;
+                    let max_bs          = read_u16be(&streaminfo[2..])?;
+                    if min_bs == max_bs {
+                        self.blk_samples = max_bs;
+                    }
+                    self.min_size       = read_u24be(&streaminfo[4..])? as usize;
+                    self.max_size       = read_u24be(&streaminfo[7..])? as usize;
+                    let word            = read_u24be(&streaminfo[10..])?;
+                    srate = word >> 4;
+                    channels = (((word >> 1) & 7) + 1) as u8;
+                    self.tot_samples    = (u64::from(streaminfo[13] & 0xF) << 32) | u64::from(read_u32be(&streaminfo[14..])?);
+                },
+                0x03 => {
+                    validate!((len % 18) == 0);
+                    seek_index.mode = SeekIndexMode::Present;
+                    for _ in 0..len / 18 {
+                        let sample      = self.src.read_u64be()?;
+                        let offset      = self.src.read_u64be()?;
+                        let _nsamps     = self.src.read_u16be()?;
+                        let time = sample * 1000 / u64::from(srate.max(1000));
+                        seek_index.add_entry(0, SeekEntry { time, pts: sample, pos: offset });
+                    }
+                },
+                _ =>                      self.src.read_skip(len)?,
+            };
+
+            if (id1 & 0x80) != 0 {
+                break;
+            }
+        }
+        self.data_start = self.src.tell();
+        validate!(srate != 0);
+
+        let base = if self.blk_samples != 0 { u32::from(self.blk_samples) } else { 1 };
+        let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, base as usize);
+        let ainfo = NACodecInfo::new("flac", NACodecTypeInfo::Audio(ahdr), Some(streaminfo));
+        strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, base, srate)).unwrap();
+
+        Ok(())
+    }
+    fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+        if self.src.is_eof() || (self.tot_samples != 0 && self.cur_samples == self.tot_samples) { return Err(DemuxerError::EOF); }
+        let mut buf = Vec::with_capacity(self.min_size);
+        let mut crc = 0;
+        for _ in 0..5 {
+            let byte                    = self.src.read_byte()?;
+            buf.push(byte);
+            crc = update_crc16(crc, byte);
+        }
+        let mut ref_crc                 = self.src.read_u16be()?;
+        loop {
+            let byte                    = self.src.read_byte()?;
+            let old_byte = (ref_crc >> 8) as u8;
+            buf.push(old_byte);
+            ref_crc = (ref_crc << 8) | u16::from(byte);
+            crc = update_crc16(crc, old_byte);
+            if buf.len() + 2 >= self.min_size && crc == ref_crc {
+                let ret                 = self.src.peek_u16be();
+                if ret.is_err() || ((ret.unwrap_or(0) & 0xFFFE) == 0xFFF8) {
+                    buf.push((ref_crc >> 8) as u8);
+                    buf.push(ref_crc as u8);
+                    break;
+                }
+            }
+            if (self.max_size > 0) && (buf.len() > self.max_size) {
+                return Err(DemuxerError::InvalidData);
+            }
+            if buf.len() > (1 << 23) {
+                return Err(DemuxerError::InvalidData);
+            }
+        }
+
+        let (duration, pts) = if self.blk_samples != 0 {
+                validate!((buf[1] & 1) == 0);
+                let blkno = u64::from(read_utf8(&buf[4..])?);
+                self.cur_samples = blkno * u64::from(self.blk_samples);
+                (u64::from(self.blk_samples), blkno)
+            } else {
+                validate!((buf[1] & 1) != 0);
+                let blksamps = u64::from(read_utf8(&buf[4..])?);
+                (blksamps, self.cur_samples)
+            };
+
+        let stream = strmgr.get_stream(0).unwrap();
+        let (tb_num, tb_den) = stream.get_timebase();
+        let ts = NATimeInfo::new(Some(pts), None, Some(duration), tb_num, tb_den);
+        let pkt = NAPacket::new(stream, ts, true, buf);
+
+        self.cur_samples += duration;
+
+        Ok(pkt)
+    }
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        let ret = seek_index.find_pos(time);
+        if ret.is_none() {
+            return Err(DemuxerError::SeekError);
+        }
+        let seek_info = ret.unwrap();
+        self.cur_samples = seek_info.pts;
+        self.src.seek(SeekFrom::Start(self.data_start + seek_info.pos))?;
+
+        Ok(())
+    }
+}
+
+impl<'a> NAOptionHandler for FLACDemuxer<'a> {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct FLACDemuxerCreator { }
+
+impl DemuxerCreator for FLACDemuxerCreator {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+        Box::new(FLACDemuxer::new(br))
+    }
+    fn get_name(&self) -> &'static str { "flac" }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+
+    #[test]
+    fn test_flac_demux() {
+        let mut file = File::open("assets/LLaudio/luckynight.flac").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = FLACDemuxer::new(&mut br);
+        let mut sm = StreamManager::new();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
+        loop {
+            let pktres = dmx.get_frame(&mut sm);
+            if let Err(e) = pktres {
+                if (e as i32) == (DemuxerError::EOF as i32) { break; }
+                panic!("error");
+            }
+            let pkt = pktres.unwrap();
+            println!("Got {}", pkt);
+        }
+    }
+}
+
+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
+];
diff --git a/nihav-llaudio/src/demuxers/mod.rs b/nihav-llaudio/src/demuxers/mod.rs
new file mode 100644 (file)
index 0000000..ce0f012
--- /dev/null
@@ -0,0 +1,33 @@
+use nihav_core::demuxers::*;
+
+#[allow(unused_macros)]
+macro_rules! validate {
+    ($a:expr) => { if !$a { println!("check failed at {}:{}", file!(), line!()); return Err(DemuxerError::InvalidData); } };
+}
+
+#[cfg(feature="demuxer_ape")]
+mod ape;
+#[cfg(feature="demuxer_flac")]
+mod flac;
+#[cfg(feature="demuxer_tta")]
+mod tta;
+#[cfg(feature="demuxer_wavpack")]
+mod wavpack;
+
+const LL_AUDIO_DEMUXERS: &[&DemuxerCreator] = &[
+#[cfg(feature="demuxer_ape")]
+    &ape::APEDemuxerCreator {},
+#[cfg(feature="demuxer_flac")]
+    &flac::FLACDemuxerCreator {},
+#[cfg(feature="demuxer_tta")]
+    &tta::TTADemuxerCreator {},
+#[cfg(feature="demuxer_wavpack")]
+    &wavpack::WavPackDemuxerCreator {},
+];
+
+/// Registers all available demuxers provided by this crate.
+pub fn llaudio_register_all_demuxers(rd: &mut RegisteredDemuxers) {
+    for demuxer in LL_AUDIO_DEMUXERS.iter() {
+        rd.add_demuxer(*demuxer);
+    }
+}
diff --git a/nihav-llaudio/src/demuxers/tta.rs b/nihav-llaudio/src/demuxers/tta.rs
new file mode 100644 (file)
index 0000000..97ee808
--- /dev/null
@@ -0,0 +1,140 @@
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+struct TTADemuxer<'a> {
+    src:            &'a mut ByteReader<'a>,
+    cur_frame:      u32,
+    nframes:        u32,
+    nsamples:       u32,
+    offtab:         Vec<u64>,
+    sizetab:        Vec<u32>,
+    framelen:       u32,
+}
+
+impl<'a> TTADemuxer<'a> {
+    fn new(io: &'a mut ByteReader<'a>) -> Self {
+        Self {
+            src:            io,
+            cur_frame:      0,
+            nframes:        0,
+            nsamples:       0,
+            offtab:         Vec::new(),
+            sizetab:        Vec::new(),
+            framelen:       0,
+        }
+    }
+}
+
+impl<'a> DemuxCore<'a> for TTADemuxer<'a> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+
+        let mut hdr = vec![0; 22];
+                                          self.src.read_buf(&mut hdr)?;
+
+        validate!(&hdr[..4] == b"TTA1");
+        let _afmt                       = read_u16le(&hdr[4..])?;
+        let channels                    = read_u16le(&hdr[6..])?;
+        validate!(channels > 0 && channels < 256);
+        let bpp                         = read_u16le(&hdr[8..])?;
+        validate!(bpp > 0 && bpp <= 32);
+        let srate                       = read_u32le(&hdr[10..])?;
+        validate!(srate > 256 && srate < 1048576);
+        self.nsamples                   = read_u32le(&hdr[14..])?;
+        validate!(self.nsamples > 0);
+        let _crc                        = read_u32le(&hdr[18..])?;
+
+        self.framelen = srate * 256 / 245;
+
+        self.nframes = (self.nsamples + self.framelen - 1) / self.framelen;
+
+        seek_index.mode = SeekIndexMode::Present;
+        let mut off = u64::from(self.nframes) * 4 + 4 + 22;
+        let mut cur_time = 0;
+        for pts in 0..self.nframes {
+            let fsize                   = self.src.read_u32le()?;
+            self.sizetab.push(fsize);
+            self.offtab.push(off);
+            let time = u64::from(cur_time) * 1000 / u64::from(srate);
+            seek_index.add_entry(0, SeekEntry { time, pts: u64::from(pts), pos: off });
+            off += u64::from(fsize);
+            cur_time += self.framelen;
+        }
+
+        let ahdr = NAAudioInfo::new(srate, channels as u8, SND_S16P_FORMAT, 1);
+        let ainfo = NACodecInfo::new("tta", NACodecTypeInfo::Audio(ahdr), Some(hdr));
+        strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, self.framelen, srate)).unwrap();
+
+        self.cur_frame = 0;
+
+        Ok(())
+    }
+    fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+        if self.cur_frame >= self.nframes {
+            return Err(DemuxerError::EOF);
+        }
+
+        let size = self.sizetab[self.cur_frame as usize] as usize;
+        let off = self.offtab[self.cur_frame as usize];
+        self.src.seek(SeekFrom::Start(off))?;
+
+        let stream = strmgr.get_stream(0).unwrap();
+        let (tb_num, tb_den) = stream.get_timebase();
+        let ts = NATimeInfo::new(Some(self.cur_frame.into()), None, None, tb_num, tb_den);
+        let pkt = self.src.read_packet(stream, ts, true, size)?;
+
+        self.cur_frame += 1;
+
+        Ok(pkt)
+    }
+    fn seek(&mut self, time: NATimePoint, seek_index: &SeekIndex) -> DemuxerResult<()> {
+        let ret = seek_index.find_pos(time);
+        if ret.is_none() {
+            return Err(DemuxerError::SeekError);
+        }
+        let seek_info = ret.unwrap();
+        self.cur_frame = seek_info.pts as u32;
+
+        Ok(())
+    }
+}
+
+impl<'a> NAOptionHandler for TTADemuxer<'a> {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+pub struct TTADemuxerCreator { }
+
+impl DemuxerCreator for TTADemuxerCreator {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+        Box::new(TTADemuxer::new(br))
+    }
+    fn get_name(&self) -> &'static str { "tta" }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+
+    #[test]
+    fn test_tta_demux() {
+        let mut file = File::open("assets/LLaudio/luckynight.tta").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = TTADemuxer::new(&mut br);
+        let mut sm = StreamManager::new();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
+        loop {
+            let pktres = dmx.get_frame(&mut sm);
+            if let Err(e) = pktres {
+                if (e as i32) == (DemuxerError::EOF as i32) { break; }
+                panic!("error");
+            }
+            let pkt = pktres.unwrap();
+            println!("Got {}", pkt);
+        }
+    }
+}
diff --git a/nihav-llaudio/src/demuxers/wavpack.rs b/nihav-llaudio/src/demuxers/wavpack.rs
new file mode 100644 (file)
index 0000000..9cfbba8
--- /dev/null
@@ -0,0 +1,296 @@
+use nihav_core::frame::*;
+use nihav_core::demuxers::*;
+
+const SAMPLE_RATES: [u32; 15] = [
+     6000,  8000,  9600, 11025, 12000, 16000,  22050, 24000,
+    32000, 44100, 48000, 64000, 88200, 96000, 192000
+];
+const WV_FLAG_MONO: u32         = 1 <<  2;
+//const WV_FLAG_HYBRID: u32       = 1 <<  3;
+//const WV_FLAG_JSTEREO: u32      = 1 <<  4;
+//const WV_FLAG_CH_DECORR: u32    = 1 <<  5;
+//const WV_FLAG_HYB_NOISE_SHAPING: u32 = 1 <<  6;
+const WV_FLAG_FLOATS: u32       = 1 <<  7;
+//const WV_FLAG_EXT_INTEGERS: u32 = 1 <<  8;
+//const WV_FLAG_HYB_BITRATE: u32  = 1 <<  9;
+//const WV_FLAG_HYB_BALANCED_NOISE: u32 = 1 << 10;
+const WV_FLAG_START_BLOCK: u32  = 1 << 11;
+const WV_FLAG_END_BLOCK: u32    = 1 << 12;
+//const WV_FLAG_HAS_CRC: u32      = 1 << 28;
+const WV_FLAG_FALSE_STEREO: u32 = 1 << 30;
+//const WV_FLAG_DSD_AUDIO: u32    = 1 << 31;
+
+const WV_STREAM_FLAGS: u32 = 0x8000018B;
+
+#[derive(Clone,Copy,Default)]
+struct WVHeader {
+    size:           usize,
+    ver:            u16,
+    tot_samples:    u64,
+    block_index:    u64,
+    block_samples:  u32,
+    flags:          u32,
+    crc:            u32,
+}
+
+const WV_HEADER_SIZE: usize = 32;
+
+impl WVHeader {
+    fn parse(src: &[u8]) -> DemuxerResult<Self> {
+        let mut mr = MemoryReader::new_read(src);
+        let mut br = ByteReader::new(&mut mr);
+        let tag                         = br.read_tag()?;
+        validate!(&tag == b"wvpk");
+        let mut hdr = Self::default();
+        hdr.size                        = br.read_u32le()? as usize;
+        validate!(hdr.size >= 24);
+        hdr.ver                         = br.read_u16le()?;
+        validate!(hdr.ver >= 0x402 || hdr.ver <= 0x410);
+        let top_idx                     = br.read_byte()?;
+        let top_samps                   = br.read_byte()?;
+        hdr.tot_samples                 = u64::from(br.read_u32le()?) | (u64::from(top_samps) << 32);
+        hdr.block_index                 = u64::from(br.read_u32le()?) | (u64::from(top_idx) << 32);
+        hdr.block_samples               = br.read_u32le()?;
+        hdr.flags                       = br.read_u32le()?;
+        hdr.crc                         = br.read_u32le()?;
+        Ok(hdr)
+    }
+    fn stream_eq(&self, rval: &Self) -> bool {
+        self.ver == rval.ver &&
+        (self.flags & WV_STREAM_FLAGS) == (rval.flags & WV_STREAM_FLAGS)
+    }
+    fn block_eq(&self, rval: &Self) -> bool {
+        self.stream_eq(rval) && self.tot_samples == rval.tot_samples &&
+        self.block_index == rval.block_index &&
+        self.block_samples == rval.block_samples
+    }
+    fn is_start_block(&self) -> bool {
+        (self.flags & WV_FLAG_START_BLOCK) != 0
+    }
+    fn is_end_block(&self) -> bool {
+        (self.flags & WV_FLAG_END_BLOCK) != 0
+    }
+    fn get_num_channels(&self) -> u8 {
+        if (self.flags & WV_FLAG_MONO) != 0 && (self.flags & WV_FLAG_FALSE_STEREO) == 0 { 1 } else { 2 }
+    }
+    fn get_sample_rate(&self) -> u32 {
+        let idx = ((self.flags >> 23) & 0xF) as usize;
+        if idx != 15 {
+            SAMPLE_RATES[idx]
+        } else {
+            0
+        }
+    }
+    fn get_size(&self) -> usize {
+        self.size - (WV_HEADER_SIZE - 8)
+    }
+}
+
+#[derive(Clone,Copy,Default)]
+struct FrameSeekInfo {
+    off:            u64,
+    samplepos:      u64,
+}
+
+struct WavPackDemuxer<'a> {
+    src:            &'a mut ByteReader<'a>,
+    samplepos:      u64,
+    nsamples:       u64,
+    first_blocks:   Option<(WVHeader, Vec<u8>)>,
+    srate:          u32,
+    known_frames:   Vec<FrameSeekInfo>,
+}
+
+impl<'a> WavPackDemuxer<'a> {
+    fn new(io: &'a mut ByteReader<'a>) -> Self {
+        Self {
+            src:            io,
+            samplepos:      0,
+            nsamples:       0,
+            first_blocks:   None,
+            srate:          0,
+            known_frames:   Vec::new(),
+        }
+    }
+    fn read_blocks(&mut self) -> DemuxerResult<(WVHeader, Vec<u8>)> {
+        let mut hdrbuf = [0u8; WV_HEADER_SIZE];
+        let mut buf: Vec<u8> = Vec::new();
+        let mut first = true;
+        let mut refhdr = WVHeader::default();
+        loop {
+                                        self.src.read_buf(&mut hdrbuf)?;
+            let hdr = WVHeader::parse(&hdrbuf)?;
+            if first {
+                validate!(hdr.is_start_block());
+                refhdr = hdr;
+                first = false;
+            } else {
+                validate!(refhdr.block_eq(&hdr));
+            }
+            buf.extend_from_slice(&hdrbuf);
+            let pos = buf.len();
+            buf.resize(pos + hdr.get_size(), 0);
+                                        self.src.read_buf(&mut buf[pos..])?;
+
+            if hdr.is_end_block() {
+                break;
+            }
+        }
+        Ok((refhdr, buf))
+    }
+}
+
+impl<'a> DemuxCore<'a> for WavPackDemuxer<'a> {
+    fn open(&mut self, strmgr: &mut StreamManager, seek_index: &mut SeekIndex) -> DemuxerResult<()> {
+
+        let (hdr, buf) = self.read_blocks()?;
+
+        let srate = hdr.get_sample_rate();
+        validate!(srate != 0);
+        let channels = if !hdr.is_end_block() {
+                let mut ch_count = 0;
+                let mut off = 0;
+                loop {
+                    let hdr = WVHeader::parse(&buf[off..]).unwrap();
+                    off += WV_HEADER_SIZE + hdr.get_size();
+                    ch_count += hdr.get_num_channels();
+                    if hdr.is_end_block() {
+                        break;
+                    }
+                }
+                ch_count
+            } else {
+                hdr.get_num_channels()
+            };
+
+        self.nsamples = hdr.tot_samples;
+
+        let mut fmt = SND_S16P_FORMAT;
+        if (hdr.flags & WV_FLAG_FLOATS) != 0 {
+            fmt.float = true;
+        } else {
+            fmt.bits = (((hdr.flags & 3) + 1) * 8) as u8;
+        }
+
+        let ahdr = NAAudioInfo::new(srate, channels, SND_S16P_FORMAT, 1);
+        let ainfo = NACodecInfo::new("wavpack", NACodecTypeInfo::Audio(ahdr), Some(buf.clone()));
+        strmgr.add_stream(NAStream::new(StreamType::Audio, 0, ainfo, 1, srate)).unwrap();
+        seek_index.mode = SeekIndexMode::Automatic;
+        self.srate = srate;
+        self.known_frames = Vec::with_capacity(((self.nsamples + u64::from(srate) - 1) / u64::from(srate)) as usize);
+        self.known_frames.push(FrameSeekInfo { off: 0, samplepos: hdr.block_index });
+
+        self.first_blocks = Some((hdr, buf));
+        Ok(())
+    }
+    fn get_frame(&mut self, strmgr: &mut StreamManager) -> DemuxerResult<NAPacket> {
+        if self.first_blocks.is_some() {
+            let mut fb = None;
+            std::mem::swap(&mut fb, &mut self.first_blocks);
+            let (refhdr, buf) = fb.unwrap();
+            let stream = strmgr.get_stream(0).unwrap();
+            let (tb_num, tb_den) = stream.get_timebase();
+            let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
+            let pkt = NAPacket::new(stream, ts, true, buf);
+
+            self.samplepos += u64::from(refhdr.block_samples);
+
+            return Ok(pkt);
+        }
+        if self.samplepos == self.nsamples {
+            return Err(DemuxerError::EOF);
+        }
+        let cur_off = self.src.tell();
+        let cur_spos = self.samplepos;
+        let (refhdr, buf) = self.read_blocks()?;
+
+        let stream = strmgr.get_stream(0).unwrap();
+        let (tb_num, tb_den) = stream.get_timebase();
+        let ts = NATimeInfo::new(Some(self.samplepos), None, None, tb_num, tb_den);
+        let pkt = NAPacket::new(stream, ts, true, buf);
+
+        self.samplepos += u64::from(refhdr.block_samples);
+        if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos < cur_spos {
+            self.known_frames.push(FrameSeekInfo{off: cur_off, samplepos: cur_spos });
+        }
+
+        Ok(pkt)
+    }
+    fn seek(&mut self, time: NATimePoint, _seek_index: &SeekIndex) -> DemuxerResult<()> {
+        self.first_blocks = None;
+        if let NATimePoint::Milliseconds(ms) = time {
+            let samppos = ms * u64::from(self.srate) / 1000;
+            if self.known_frames.last().unwrap_or(&FrameSeekInfo::default()).samplepos >= samppos {
+                for point in self.known_frames.iter().rev() {
+                    if point.samplepos <= samppos {
+                        self.src.seek(SeekFrom::Start(point.off))?;
+                        self.samplepos = point.samplepos;
+                        return Ok(());
+                    }
+                }
+            } else {
+                let mut hdrbuf = [0u8; WV_HEADER_SIZE];
+                loop {
+                                          self.src.peek_buf(&mut hdrbuf)?;
+                    let hdr = WVHeader::parse(&hdrbuf)?;
+                    if hdr.is_start_block() {
+                        self.known_frames.push(FrameSeekInfo{off: self.src.tell(), samplepos: hdr.block_index });
+                        if hdr.block_index <= samppos && hdr.block_index + u64::from(hdr.block_samples) > samppos {
+                            self.samplepos = hdr.block_index;
+                            return Ok(());
+                        }
+                        if hdr.block_index > samppos {
+                            break;
+                        }
+                    }
+                                          self.src.read_skip(WV_HEADER_SIZE + hdr.get_size())?
+                }
+            }
+            Err(DemuxerError::SeekError)
+        } else {
+            Err(DemuxerError::NotPossible)
+        }
+    }
+}
+
+impl<'a> NAOptionHandler for WavPackDemuxer<'a> {
+    fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
+    fn set_options(&mut self, _options: &[NAOption]) { }
+    fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
+}
+
+
+pub struct WavPackDemuxerCreator { }
+
+impl DemuxerCreator for WavPackDemuxerCreator {
+    fn new_demuxer<'a>(&self, br: &'a mut ByteReader<'a>) -> Box<dyn DemuxCore<'a> + 'a> {
+        Box::new(WavPackDemuxer::new(br))
+    }
+    fn get_name(&self) -> &'static str { "wavpack" }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use std::fs::File;
+
+    #[test]
+    fn test_wavpack_demux() {
+        let mut file = File::open("assets/LLaudio/wv/false_stereo.wv").unwrap();
+        let mut fr = FileReader::new_read(&mut file);
+        let mut br = ByteReader::new(&mut fr);
+        let mut dmx = WavPackDemuxer::new(&mut br);
+        let mut sm = StreamManager::new();
+        let mut si = SeekIndex::new();
+        dmx.open(&mut sm, &mut si).unwrap();
+        loop {
+            let pktres = dmx.get_frame(&mut sm);
+            if let Err(e) = pktres {
+                if (e as i32) == (DemuxerError::EOF as i32) { break; }
+                panic!("error");
+            }
+            let pkt = pktres.unwrap();
+            println!("Got {}", pkt);
+        }
+    }
+}
diff --git a/nihav-llaudio/src/lib.rs b/nihav-llaudio/src/lib.rs
new file mode 100644 (file)
index 0000000..abe4694
--- /dev/null
@@ -0,0 +1,10 @@
+extern crate nihav_core;
+extern crate nihav_codec_support;
+
+#[allow(clippy::unreadable_literal)]
+#[allow(clippy::verbose_bit_mask)]
+mod codecs;
+#[allow(clippy::unreadable_literal)]
+mod demuxers;
+pub use crate::codecs::llaudio_register_all_decoders;
+pub use crate::demuxers::llaudio_register_all_demuxers;
index 6f67fbd7253502f17f82a212d8bfce2a6eb531a0..210d0008faa25b5540ce0eb1bde16241dd4d960c 100644 (file)
@@ -254,6 +254,28 @@ const DETECTORS: &[DetectConditions] = &[
         extensions: ".smk",
         conditions: &[CheckItem{offs: 0, cond: &CC::Or(&CC::Str(b"SMK2"), &CC::Str(b"SMK4"))}],
     },
+    DetectConditions {
+        demux_name: "ape",
+        extensions: ".ape",
+        conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"MAC ") },
+                      CheckItem{offs: 4, cond: &CC::In(Arg::U16LE(3800), Arg::U16LE(3990))}],
+    },
+    DetectConditions {
+        demux_name: "flac",
+        extensions: ".flac",
+        conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"fLaC") }],
+    },
+    DetectConditions {
+        demux_name: "tta",
+        extensions: ".tta",
+        conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"TTA1") }],
+    },
+    DetectConditions {
+        demux_name: "wavpack",
+        extensions: ".wv",
+        conditions: &[CheckItem{offs: 0, cond: &CC::Str(b"wvpk") },
+                      CheckItem{offs: 8, cond: &CC::In(Arg::U16LE(0x402), Arg::U16LE(0x410))}],
+    },
     DetectConditions {
         demux_name: "vivo",
         extensions: ".viv",
index 0accdd4e6263307ab0986bf4a452381d0e22421c..fdf9e83d855485c44968a1a0d1488e00dee7ebdd 100644 (file)
@@ -137,6 +137,10 @@ macro_rules! desc {
         CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
                           caps: CODEC_CAP_LOSSLESS | CODEC_CAP_INTRAONLY }
     });
+    (audio-hyb; $n:expr, $fn:expr) => ({
+        CodecDescription{ name: $n, fname: $fn, ctype: CodecType::Audio,
+                          caps: CODEC_CAP_HYBRID }
+    });
 }
 
 /// Returns codec description for the provided codec short name if it is found.
@@ -245,6 +249,11 @@ static CODEC_REGISTER: &'static [CodecDescription] = &[
     desc!(video;    "vivo2",         "VivoActive Video 2.0", CODEC_CAP_REORDER),
     desc!(audio;    "g723.1",        "ITU G.723.1"),
     desc!(audio;    "siren",         "Polycom Siren"),
+
+    desc!(audio-ll;  "ape",          "Monkey's Audio"),
+    desc!(audio-ll;  "flac",         "Free Lossless Audio Codec"),
+    desc!(audio-ll;  "tta",          "True Audio codec"),
+    desc!(audio-hyb; "wavpack",      "WavPack"),
 ];
 
 static AVI_VIDEO_CODEC_REGISTER: &'static [(&[u8;4], &str)] = &[