lewton-0.10.2/.cargo_vcs_info.json0000644000000001121400210240300124360ustar { "git": { "sha1": "9e377e1693685ff82d58807b261631619ca92748" } } lewton-0.10.2/.editorconfig010066400017500001750000000002441367240530400137460ustar 00000000000000# top-most EditorConfig file root = true [*] indent_style = tab tab_width = 4 end_of_line=lf charset=utf-8 trim_trailing_whitespace=true insert_final_newline=true lewton-0.10.2/.github/workflows/lewton.yml010066400017500001750000000020231376362026100167200ustar 00000000000000name: lewton on: [push, pull_request] jobs: build: strategy: matrix: os: [macOS-latest, ubuntu-latest, windows-latest] toolchain: [stable, 1.45.0, 1.36.0] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@master - name: Install Rust if: matrix.os != 'macOS-latest' || matrix.toolchain != '1.36.0' uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} override: true - name: Run no-default-features builds if: matrix.os != 'macOS-latest' || matrix.toolchain != '1.36.0' run: | cargo test --verbose --no-default-features cargo doc --verbose --no-default-features - name: Run all-features builds if: matrix.os != 'macOS-latest' || matrix.toolchain != '1.36.0' run: | cargo test --verbose --all-features cargo doc --verbose --all-features - name: Run cmp tests if: matrix.toolchain == '1.45.0' run: | cd dev/cmp cargo test --verbose --release lewton-0.10.2/.gitignore010066400017500001750000000000501367240530400132540ustar 00000000000000target *swp callgrind.out.* test-assets lewton-0.10.2/.rustfmt.toml010066400017500001750000000015221373056706200137550ustar 00000000000000# Note that this rustfmt file only provides rough # guidelines about how the style should be. # Right now, rustfmt is not capable to map all # demands to the code style (yet). hard_tabs = true normalize_comments = false max_width = 120 ideal_width = 100 space_before_type_annotation = true space_before_bound = false space_after_type_annotation_colon = false space_after_bound_colon = true spaces_around_ranges = true match_block_trailing_comma = true match_wildcard_trailing_comma = true wrap_match_arms = false fn_brace_style = "PreferSameLine" item_brace_style = "PreferSameLine" fn_args_layout = "Block" where_pred_indent = "Block" generics_indent = "Block" struct_lit_style = "Block" fn_call_style = "Block" chain_indent = "Block" take_source_hints = true trailing_comma = "Vertical" fn_args_density = "Compressed" where_density = "Compressed" lewton-0.10.2/CHANGELOG.md010066400017500001750000000117021400210126300130640ustar 00000000000000# Changes ## Release 0.10.2 - January 20, 2021 * Updated ogg to 0.8 * Updated tinyvec to 1.0 * Testsuite fixes. Thanks to [@nico-abram](https://github.com/nico-abram) for their help! ## Release 0.10.1 - March 16, 2020 * Removed deprecated Error descriptions * Swapped smallvec for tinyvec. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the contribution! ## Release 0.10.0 - January 30, 2020 * MSRV increased to 1.36.0. This is mainly because smallvec needs 1.36.0 now. * Updated to smallvec 1.0. Thanks to [@repi](https://github.com/repi) for the contribution! * C API via cbingen/cargo-c. Thanks to [@lu-zero](https://github.com/lu-zero) for the contribution! * Various simplifications in audio.rs. Thanks to [@AnthonyMikh](https://github.com/AnthonyMikh) for the contribution! * Moved from Travis CI to Github Actions. Thanks to [@Luni-4](https://github.com/Luni-4) for the contribution! * Adopted a workspace to have a common Cargo.lock file. ## Release 0.9.4 - March 08, 2019 * Added a function to obtain the stream serial from an `OggStreamReader` * Invalid UTF-8 strings in comment headers are now silently omitted * Allowed to specify floats as output format * Fixed multiple bugs on fuzzed inputs ## Release 0.9.3 - October 28, 2018 * Fixed wrongly decoded files. Now, not a single mismatch to libvorbis is left on the xiph and libnogg test vectors (issue [#26](https://github.com/RustAudio/lewton/issues/26)) * Updated ogg to 0.7.0 ## Release 0.9.2 - October 07, 2018 * Fixed a wrongly decoded file bug (issue [#24](https://github.com/RustAudio/lewton/issues/24)) ## Release 0.9.1 - September 22, 2018 * Performance improvements of about 10%. Thanks to [@GabrielMajeri](https://github.com/GabrielMajeri) for the contribution! * Fixed some wrongly decoded files * Fixed some panics on crafted input. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the fuzzing and bug reports. * Added travis CI ## Release 0.9.0 - August 16, 2018 * Renamed `async` to `async_api` for better edition 2018 compilance * Updated ogg to 0.6.0 * Expanded test suite to include xiph test vectors * Support for chained files ## Release 0.8.0 - February 7, 2018 * Removed unused error enum variant * Pub used OggReadError so that people can match on its variants without needing to depend on the Ogg crate * Used min instead of residue_begin/residue_end directly. See also [the PR](https://github.com/xiph/vorbis/pull/35) that modified the vorbis spec accordingly. ## Release 0.7.0 - October 24, 2017 * Removed all uses of unsafe in return of making Rust 1.20 required ## Release 0.6.2 - June 18, 2017 * Exposed blockize_0 and blocksize_1 in the public API of the ident header again, so that lewton can be used without ogg encapsulation. ## Release 0.6.1 - June 8, 2017 * Fix a doc link ## Release 0.6.0 - June 8, 2017 * Made parts of the API that are not intended for the public crate local * Added seeking support with a granularity of pages * Updated to ogg to 0.5.0 * The async support now doesn't need unstable features any more, and bases on tokio ## Release 0.5.2 - May 13, 2017 * Removed two unused macros to prevent warnings about them ## Release 0.5.1 - April 30, 2017 * Bugfix to work on newest Rust nightly/beta * Bugfix to work with the alto crate instead of openal-rs which has been yanked * Bugfix in the player example for duration calculation ## Release 0.5 - February 15, 2017 * New, more convenient, constructor for OggStreamReader. * Updated to Byteorder 1.0. ## Release 0.4.1 - November 17, 2016 * Fixed a panic issue with reading huffman trees. ## Release 0.4 - October 4, 2016 * Updated ogg. * Made the `inside_ogg` API own the reader. ## Release 0.3 - October 4, 2016 * Added support for floor 0. It is not used in practice anymore, but now all features of the vorbis format are supported. * Improved the API for reading decoded packets. * Fixed a bug in comment header parsing. * Various minor simplifications. * Improved the cmp tool. You can now compare our output to libvorbis with `cargo test --release -- --nocapture`, and our speed with `cargo run --release bench`. ## Release 0.2 - September 13, 2016 * Improved speed by about 20%. * Added async ready API to the `inside_ogg` module to work with async IO. Still behind a feature as it relies on the unstable [specialisation feature](https://github.com/rust-lang/rust/issues/31844). * Removed parts of the API that were irrelevant to users of the crate. This gives a better overview for our users. Unfortunately due to [pub(crate) not being stable yet](https://github.com/rust-lang/rust/issues/32409), not all parts of the API could have been made private. * Examples are CC-0 now, this should ease adoption. * Documentation improvements * Implemented a tool to compare our speed and output with libvorbis. To see how correct this crate is, cd to `dev/cmp` and do `cargo run --release vals /path/to/test_file.ogg`. For speed tests, swap "vals" with "perf". ## Release 0.1 - September 1, 2016 Initial release. lewton-0.10.2/Cargo.lock0000644000000344151400210240300104260ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. [[package]] name = "al-sys" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "rental 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "alto" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "al-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "byteorder" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bytes" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cmake" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "fuchsia-cprng" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "iovec" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lewton" version = "0.10.2" dependencies = [ "alto 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "ogg 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "tinyvec 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" version = "0.2.66" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libloading" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "maybe-uninit" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "ogg" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "owning_ref" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "parking_lot_core" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "proc-macro2" version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rdrand" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rental" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "rental-impl 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rental-impl" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "smallvec" version = "0.6.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tinyvec" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tinyvec_macros" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "tokio-io" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum al-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8d9b0f4d10264c060ee5614dedb6b7695f366e93be6549c48f58981da39023" "checksum alto 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "d75be812fc4f27ac66752f30715a2357c9f3ad619229fc21cf431b32606dfae5" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cmake 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "81fb25b677f8bf1eb325017cb6bb8452f87969db0fedb4f757b297bee78a7c62" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1b980f2816d6ee8673b6517b52cb0e808a180efc92e5c19d02cdda79066703ef" "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" "checksum libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b111a074963af1d37a139918ac6d49ad1d0d5e47f72fd55388619691a7d753" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum ogg 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e" "checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37" "checksum parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "149d8f5b97f3c1133e3cfcd8886449959e856b557ff281e292b733d7c69e005e" "checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa" "checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum rental 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "8545debe98b2b139fb04cad8618b530e9b07c152d99a5de83c860b877d67847f" "checksum rental-impl 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "475e68978dc5b743f2f40d8e0a8fdc83f1c5e78cbf4b8fa5e74e73beebc340de" "checksum smallvec 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0758c52e15a8b5e3691eae6cc559f08eee9406e548a4477ba4e67770a82b6" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" "checksum syn 1.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "af6f3550d8dff9ef7dc34d384ac6f107e5d31c8f57d9f28e0081503f547ac8f5" "checksum tinyvec 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b78a366903f506d2ad52ca8dc552102ffdd3e937ba8a227f024dc1d1eae28575" "checksum tinyvec_macros 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" "checksum tokio-io 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5090db468dad16e1a7a54c8c67280c5e4b544f3d3e018f0b913b400261f85926" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" lewton-0.10.2/Cargo.toml0000644000000030221400210240300104370ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies # # If you believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2015" name = "lewton" version = "0.10.2" authors = ["est31 "] description = "Pure Rust vorbis decoder" documentation = "https://docs.rs/lewton" readme = "README.md" keywords = ["ogg", "vorbis", "decoder", "audio"] categories = ["compression", "multimedia::audio", "multimedia::encoding"] license = "MIT OR Apache-2.0" repository = "https://github.com/RustAudio/lewton" [package.metadata.docs.rs] features = ["async_ogg"] [lib] name = "lewton" [[example]] name = "perf" required-features = ["ogg"] [[example]] name = "player" required-features = ["ogg"] [dependencies.byteorder] version = "1.0" [dependencies.futures] version = "0.1" optional = true [dependencies.ogg] version = "0.8" optional = true [dependencies.tinyvec] version = "1.0" features = ["alloc"] [dependencies.tokio-io] version = "0.1" optional = true [dev-dependencies.alto] version = "3" [dev-dependencies.ogg] version = "0.8" [features] async_ogg = ["ogg", "ogg/async", "futures", "tokio-io"] default = ["ogg"] lewton-0.10.2/Cargo.toml.orig010066400017500001750000000017331400210126300141450ustar 00000000000000[workspace] members = ["dev/cmp"] [package] name = "lewton" version = "0.10.2" authors = ["est31 "] description = "Pure Rust vorbis decoder" license = "MIT OR Apache-2.0" repository = "https://github.com/RustAudio/lewton" keywords = ["ogg", "vorbis", "decoder", "audio"] categories = ["compression", "multimedia::audio", "multimedia::encoding"] documentation = "https://docs.rs/lewton" readme = "README.md" edition = "2015" [features] default = ["ogg"] async_ogg = ["ogg", "ogg/async", "futures", "tokio-io"] [[example]] name = "perf" required-features = ["ogg"] [[example]] name = "player" required-features = ["ogg"] [dependencies] byteorder = "1.0" tinyvec = { version = "1.0", features = ["alloc"] } ogg = { version = "0.8", optional = true } tokio-io = { version = "0.1", optional = true } futures = { version = "0.1", optional = true } [dev-dependencies] ogg = "0.8" alto = "3" [package.metadata.docs.rs] features = ["async_ogg"] [lib] name = "lewton" lewton-0.10.2/LICENSE010066400017500001750000000266141343710651200123050ustar 00000000000000Copyright (c) 2016 est31 and contributors Licensed under MIT or Apache License 2.0, at your option. The full list of contributors can be obtained by looking at the VCS log (originally, this crate was git versioned, there you can do "git shortlog -sn" for this task). MIT License ----------- The MIT License (MIT) Copyright (c) 2016 est31 and contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Apache License, version 2.0 --------------------------- Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS lewton-0.10.2/README.md010066400017500001750000000060321367355157400125650ustar 00000000000000# lewton [![docs](https://docs.rs/lewton/badge.svg)](https://docs.rs/crate/lewton) [![crates.io](https://img.shields.io/crates/v/lewton.svg)](https://crates.io/crates/lewton) [![dependency status](https://deps.rs/repo/github/rustaudio/lewton/status.svg)](https://deps.rs/repo/github/rustaudio/lewton) Vorbis decoder written in pure Rust. To give the decoder a try, you can do: ```sh cargo run --example player /path/to/your/audio_file.ogg ``` It will then play back the audio. If you want to know how to use this crate, look at the examples folder. This crate has a low level API for per-packet decoding in the `audio` and `header` modules, and a high level API for ogg/vorbis streams in the `inside_ogg` module. Some parts were created with help from the public domain [stb_vorbis](http://nothings.org/stb_vorbis/) decoder implementation. The minimum required Rust version is 1.36. ## Use of unsafe The entire library uses not a single line of unsafe code. In fact, lib.rs contains the `#![forbid(unsafe_code)]` directive. ## About the history of this crate I've started started to work on this crate in December 2015. The goal was to learn more about Rust and audio processing, while also delivering something useful to the Rust ecosystem. I've tried not to look into the libvorbis implementation, as then I'd have to first abide the BSD license, and second as I didn't want this crate to become "just" a translation from C to Rust. Instead I wanted this crate to base on the spec only, so that I'd learn more about how vorbis worked. The only time I did look into the libvorbis implementation was to look up the implementation of a function needed by the ogg crate (the CRC function), which is why that crate is BSD licensed, and attributes the authors. This crate however contains no code, translated or otherwise, from the libvorbis implementation. After some time I realized that without any help of a working implementation progress would become too slow. Therefore, I've continued to work with the public domain `stb_vorbis` implementation and used some of its code (most prominently for the imdct algorithm) to translate it to rust. I've also used it for debugging by comparing its outputs with mine. Most of this crate however was created by reading the spec only. ## Use from C **lewton** provides a C-compatible set of library, header and pkg-config file. To build and install it you can use [cargo-c](https://crates.io/crates/cargo-c): ```sh cargo install cargo-c cargo cinstall --release --destdir /tmp/lewton sudo cp -a /tmp/lewton/* / ``` ## License Licensed under Apache 2 or MIT (at your option). For details, see the [LICENSE](LICENSE) file. All examples inside the `examples/` folder are licensed under the [CC-0](https://creativecommons.org/publicdomain/zero/1.0/) license. ### License of your contributions Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed / CC-0 licensed as above, without any additional terms or conditions. lewton-0.10.2/cbindgen.toml010066400017500001750000000003161367355157400137530ustar 00000000000000header = "// SPDX-License-Identifier: MIT OR Apache-2.0" sys_includes = ["stddef.h", "stdint.h", "stdlib.h"] no_includes = true include_guard = "LEWTON_LEWTON_H" tab_width = 4 style = "Type" language = "C" lewton-0.10.2/examples/perf.rs010066400017500001750000000025251367240530400144150ustar 00000000000000// Vorbis decoder written in Rust // // This example file is licensed // under the CC-0 license: // https://creativecommons.org/publicdomain/zero/1.0/ extern crate lewton; extern crate byteorder; fn main() { match run() { Ok(_) =>(), Err(err) => println!("Error: {}", err), } } use std::env; use lewton::VorbisError; use lewton::inside_ogg::OggStreamReader; use std::fs::File; use std::time::Instant; pub fn run() -> Result<(), VorbisError> { let file_path = env::args().nth(1).expect("No arg found. Please specify a file to open."); println!("Opening file: {}", file_path); let f = File::open(file_path).expect("Can't open file"); let mut srr = try!(OggStreamReader::new(f)); println!("Sample rate: {}", srr.ident_hdr.audio_sample_rate); // Now the fun starts.. let mut n = 0; let mut len_play = 0.0; let start_decode_time = Instant::now(); while let Some(pck) = try!(srr.read_dec_packet()) { n += 1; // This is guaranteed by the docs assert_eq!(pck.len(), srr.ident_hdr.audio_channels as usize); len_play += pck[0].len() as f32 / srr.ident_hdr.audio_sample_rate as f32; } let decode_duration = Instant::now() - start_decode_time; println!("The piece is {} s long ({} packets).", len_play, n); println!("Decoded in {} s.", decode_duration.as_secs() as f64 + (decode_duration.subsec_nanos() as f64) / 1_000_000_000.0); Ok(()) } lewton-0.10.2/examples/player.rs010066400017500001750000000053271367240530400147600ustar 00000000000000// Vorbis decoder written in Rust // // This example file is licensed // under the CC-0 license: // https://creativecommons.org/publicdomain/zero/1.0/ extern crate alto; extern crate lewton; extern crate byteorder; use std::env; use lewton::VorbisError; use lewton::inside_ogg::OggStreamReader; use std::fs::File; use std::thread::sleep; use std::time::{Instant, Duration}; use alto::{Alto, Mono, Stereo, Source}; fn main() { match run() { Ok(_) =>(), Err(err) => println!("Error: {}", err), } } fn run() -> Result<(), VorbisError> { let file_path = env::args().nth(1).expect("No arg found. Please specify a file to open."); println!("Opening file: {}", file_path); let f = File::open(file_path).expect("Can't open file"); // Prepare the reading let mut srr = try!(OggStreamReader::new(f)); // Prepare the playback. let al = Alto::load_default().expect("Could not load alto"); let device = al.open(None).expect("Could not open device"); let cxt = device.new_context(None).expect("Could not create context"); let mut str_src = cxt.new_streaming_source() .expect("could not create streaming src"); let sample_rate = srr.ident_hdr.audio_sample_rate as i32; if srr.ident_hdr.audio_channels > 2 { // the openal crate can't process these many channels directly println!("Stream error: {} channels are too many!", srr.ident_hdr.audio_channels); } println!("Sample rate: {}", srr.ident_hdr.audio_sample_rate); // Now the fun starts.. let mut n = 0; let mut len_play = 0.0; let mut start_play_time = None; let start_decode_time = Instant::now(); let sample_channels = srr.ident_hdr.audio_channels as f32 * srr.ident_hdr.audio_sample_rate as f32; while let Some(pck_samples) = try!(srr.read_dec_packet_itl()) { println!("Decoded packet no {}, with {} samples.", n, pck_samples.len()); n += 1; let buf = match srr.ident_hdr.audio_channels { 1 => cxt.new_buffer::,_>(&pck_samples, sample_rate), 2 => cxt.new_buffer::,_>(&pck_samples, sample_rate), n => panic!("unsupported number of channels: {}", n), }.unwrap(); str_src.queue_buffer(buf).unwrap(); len_play += pck_samples.len() as f32 / sample_channels; // If we are faster than realtime, we can already start playing now. if n == 100 { let cur = Instant::now(); if cur - start_decode_time < Duration::from_millis((len_play * 1000.0) as u64) { start_play_time = Some(cur); str_src.play(); } } } let total_duration = Duration::from_millis((len_play * 1000.0) as u64); let sleep_duration = total_duration - match start_play_time { None => { str_src.play(); Duration::from_millis(0) }, Some(t) => (Instant::now() - t) }; println!("The piece is {} s long.", len_play); sleep(sleep_duration); Ok(()) } lewton-0.10.2/src/audio.rs010066400017500001750000001137671376463273200135570ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Audio packet decoding This module decodes the audio packets given to it. */ #[allow(unused_imports)] use imdct; use std::error; use std::fmt; use std::cmp::min; use std::iter; use tinyvec::TinyVec; use ::ilog; use ::bitpacking::BitpackCursor; use ::header::{Codebook, Floor, FloorTypeZero, FloorTypeOne, HuffmanVqReadErr, IdentHeader, Mapping, Residue, SetupHeader}; use samples::Samples; #[derive(Debug, PartialEq, Eq)] pub enum AudioReadError { EndOfPacket, AudioBadFormat, AudioIsHeader, /// If the needed memory isn't addressable by us /// /// This error is returned if a calculation yielded a higher value for /// an internal buffer size that doesn't fit into the platform's address range. /// Note that if we "simply" encounter an allocation failure (OOM, etc), /// we do what libstd does in these cases: crash. /// /// This error is not automatically an error of the format, /// but rather is due to insufficient decoder hardware. BufferNotAddressable, } // For the () error type returned by the bitpacking layer // TODO that type choice was a bit unfortunate, // perhaps one day fix this impl From<()> for AudioReadError { fn from(_ :()) -> AudioReadError { AudioReadError::EndOfPacket } } impl error::Error for AudioReadError {} impl fmt::Display for AudioReadError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { let description = match self { AudioReadError::EndOfPacket => "End of packet reached.", AudioReadError::AudioBadFormat => "Invalid audio packet", AudioReadError::AudioIsHeader => "The vorbis version is not supported", AudioReadError::BufferNotAddressable => "Requested to create buffer of non-addressable size", }; write!(fmt, "{}", description) } } enum DecodedFloor<'a> { TypeZero(Vec, u64, &'a FloorTypeZero), TypeOne(Vec, &'a FloorTypeOne), Unused, } impl <'a> DecodedFloor<'a> { fn is_unused(&self) -> bool { match self { &DecodedFloor::Unused => true, _ => false, } } } enum FloorSpecialCase { Unused, PacketUndecodable, } impl From<()> for FloorSpecialCase { fn from(_ :()) -> Self { // () always means end of packet condition in the places // the conversion is used. return FloorSpecialCase::Unused; } } impl From for FloorSpecialCase { fn from(e :HuffmanVqReadErr) -> Self { use ::header::HuffmanVqReadErr::*; use self::FloorSpecialCase::*; match e { EndOfPacket => Unused, // Undecodable per spec, see paragraph about // VQ lookup type zero in section 3.3. NoVqLookupForCodebook => PacketUndecodable, } } } // Note that the output vector contains the cosine values of the coefficients, // not the bare values like in the spec. This is in order to optimize. fn floor_zero_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook], fl :&FloorTypeZero) -> Result<(Vec, u64), FloorSpecialCase> { // TODO this needs to become 128 bits wide, not just 64, // as floor0_amplitude_bits can be up to 127. let amplitude = try!(rdr.read_dyn_u64(fl.floor0_amplitude_bits)); if amplitude <= 0 { // This channel is unused in this frame, // its all zeros. return Err(FloorSpecialCase::Unused); } let booknumber = try!(rdr.read_dyn_u32( ::ilog(fl.floor0_number_of_books as u64))); match fl.floor0_book_list.get(booknumber as usize) { // Undecodable per spec None => try!(Err(FloorSpecialCase::PacketUndecodable)), Some(codebook_idx) => { let mut coefficients = Vec::with_capacity(fl.floor0_order as usize); let mut last = 0.0; let codebook = &codebooks[*codebook_idx as usize]; loop { let mut last_new = last; let temp_vector = try!(rdr.read_huffman_vq(codebook)); if temp_vector.len() + coefficients.len() < fl.floor0_order as usize { // Little optimisation: we don't have to care about the >= case here for &e in temp_vector { coefficients.push((last + e as f32).cos()); last_new = e as f32; } } else { for &e in temp_vector { coefficients.push((last + e as f32).cos()); last_new = e as f32; // This rule makes sure that coefficients doesn't get // larger than floor0_order and saves an allocation // in this case if coefficients.len() == fl.floor0_order as usize { return Ok((coefficients, amplitude)); } } } last += last_new; if coefficients.len() >= fl.floor0_order as usize { return Ok((coefficients, amplitude)); } } }, } unreachable!(); } fn floor_zero_compute_curve(cos_coefficients :&[f32], amplitude :u64, fl :&FloorTypeZero, blockflag :bool, n :u16) -> Vec { let cached_bark_cos_omega = &fl.cached_bark_cos_omega[blockflag as usize]; let mut i = 0; let mut output = Vec::with_capacity(n as usize); let lfv_common_term = amplitude as f32 * fl.floor0_amplitude_offset as f32 / ((1 << fl.floor0_amplitude_bits) - 1) as f32; while i < n as usize { let cos_omega = cached_bark_cos_omega[i]; // Compute p and q let (p_upper_border, q_upper_border) = if fl.floor0_order & 1 == 1 { ((fl.floor0_order as usize - 3) / 2, (fl.floor0_order as usize - 1) / 2) } else { let v = (fl.floor0_order as usize - 2) / 2; (v, v) }; let (mut p, mut q) = if fl.floor0_order & 1 == 1 { (1.0 - cos_omega * cos_omega, 0.25) } else { ((1.0 - cos_omega) / 2.0, (1.0 + cos_omega) / 2.0) }; for j in 0 .. p_upper_border + 1 { let pm = cos_coefficients[2 * j + 1] - cos_omega; p *= 4.0 * pm * pm; } for j in 0 .. q_upper_border + 1 { let qm = cos_coefficients[2 * j] - cos_omega; q *= 4.0 * qm * qm; } // Compute linear_floor_value let linear_floor_value = (0.11512925 * (lfv_common_term / (p+q).sqrt() - fl.floor0_amplitude_offset as f32) ).exp(); // Write into output let mut iteration_condition = cos_omega; while cos_omega == iteration_condition { output.push(linear_floor_value); i += 1; iteration_condition = match cached_bark_cos_omega.get(i) { Some(v) => *v, None => break, }; } } return output; } // Returns Err if the floor is "unused" fn floor_one_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook], fl :&FloorTypeOne) -> Result, FloorSpecialCase> { // TODO perhaps it means invalid audio packet if reading the nonzero // flag doesn't succeed bc end of packet. Perhaps it does not. if !try!(rdr.read_bit_flag()) { try!(Err(())); } let mut floor1_y = Vec::new(); let v = &[256, 128, 86, 64]; let range = v[(fl.floor1_multiplier - 1) as usize]; let b = ::ilog(range - 1); floor1_y.push(try!(rdr.read_dyn_u8(b)) as u32); floor1_y.push(try!(rdr.read_dyn_u8(b)) as u32); for class in &fl.floor1_partition_class { let uclass = *class as usize; let cdim = fl.floor1_class_dimensions[uclass]; let cbits = fl.floor1_class_subclasses[uclass]; let csub = (1 << cbits) - 1; let mut cval = 0; if cbits > 0 { let cbook = fl.floor1_class_masterbooks[uclass] as usize; cval = try!(rdr.read_huffman(&codebooks[cbook].codebook_huffman_tree)); } for _ in 0 .. cdim { let book = fl.floor1_subclass_books[uclass][(cval & csub) as usize]; cval >>= cbits; if book >= 0 { let tree = &codebooks[book as usize].codebook_huffman_tree; floor1_y.push(try!(rdr.read_huffman(tree))); } else { floor1_y.push(0); } } } return Ok(floor1_y); } fn extr_neighbor(v :&[u32], max_idx :usize, compare :F, relation :&str) -> (usize, u32) where F :Fn(u32, u32) -> std::cmp::Ordering { use std::cmp::Ordering; let bound = v[max_idx]; let prefix = &v[..max_idx]; let smaller = |a, b| compare(a, b) == Ordering::Less; // First find a first index that fulfills // the criterion of being "smaller" than bound let min_idx = prefix.iter() .position(|&val| smaller(val, bound)) .unwrap_or_else(|| panic!("No index y < {0} found where v[y] is {1} than v[{0}] = 0x{2:08x}!", max_idx, relation, bound)); // Now search for "bigger" entries let (offset, max_neighbor) = prefix[min_idx..].iter().cloned() .enumerate() // According to documentation of Iterator::max_by, // "If several elements are equally maximum, the last element is returned". // Thus, in order to find the *first* maximum element, // we need to search from the end of `prefix` .rev() .filter(|&(_i, val)| smaller(val, bound)) .max_by(|&(_, a), &(_, b)| compare(a, b)) .unwrap_or((0, v[min_idx])); (min_idx + offset, max_neighbor) } fn low_neighbor(v :&[u32], x :usize) -> (usize, u32) { extr_neighbor(v, x, |a, b| a.cmp(&b), "smaller") } fn high_neighbor(v :&[u32], x :usize) -> (usize, u32) { extr_neighbor(v, x, |a, b| b.cmp(&a), "bigger") } #[test] fn test_low_neighbor() { let v = [1, 4, 2, 3, 6, 5]; // 0 will panic assert_eq!(low_neighbor(&v, 1), (0, 1)); assert_eq!(low_neighbor(&v, 2), (0, 1)); assert_eq!(low_neighbor(&v, 3), (2, 2)); assert_eq!(low_neighbor(&v, 4), (1, 4)); assert_eq!(low_neighbor(&v, 5), (1, 4)); } #[test] fn test_high_neighbor() { let v = [1, 4, 2, 3, 6, 5]; // 0, 1 will panic assert_eq!(high_neighbor(&v, 2), (1, 4)); assert_eq!(high_neighbor(&v, 3), (1, 4)); // 4 will panic assert_eq!(high_neighbor(&v, 5), (4, 6)); } #[test] fn test_high_neighbor_ex() { // Data extracted from example file let v = [0, 128, 12, 46, 4, 8, 16, 23, 33, 70, 2, 6, 10, 14, 19, 28, 39, 58, 90]; // 0, 1 will panic assert_eq!(high_neighbor(&v, 2), (1, 128)); assert_eq!(high_neighbor(&v, 3), (1, 128)); assert_eq!(high_neighbor(&v, 4), (2, 12)); assert_eq!(high_neighbor(&v, 5), (2, 12)); assert_eq!(high_neighbor(&v, 6), (3, 46)); assert_eq!(high_neighbor(&v, 7), (3, 46)); assert_eq!(high_neighbor(&v, 8), (3, 46)); assert_eq!(high_neighbor(&v, 9), (1, 128)); assert_eq!(high_neighbor(&v, 10), (4, 4)); assert_eq!(high_neighbor(&v, 11), (5, 8)); assert_eq!(high_neighbor(&v, 12), (2, 12)); assert_eq!(high_neighbor(&v, 13), (6, 16)); assert_eq!(high_neighbor(&v, 14), (7, 23)); assert_eq!(high_neighbor(&v, 15), (8, 33)); assert_eq!(high_neighbor(&v, 16), (3, 46)); assert_eq!(high_neighbor(&v, 17), (9, 70)); assert_eq!(high_neighbor(&v, 18), (1, 128)); } #[test] #[should_panic] fn test_high_neighbor_panic() { high_neighbor(&[1, 4, 3, 2, 6, 5], 4); } #[test] #[should_panic] fn test_low_neighbor_panic() { low_neighbor(&[2, 4, 3, 1, 6, 5], 3); } fn render_point(x0 :u32, y0 :u32, x1 :u32, y1 :u32, x :u32) -> u32 { // TODO find out whether the type choices in this method are okay // (esp. the i32 choice). let dy = y1 as i32 - y0 as i32; let adx = x1 - x0; let ady = dy.abs() as u32; let err = ady * (x - x0); let off = err / adx; if dy < 0 { return y0 - off; } else { return y0 + off; } } #[test] fn test_render_point() { // Test data taken from real life ogg/vorbis file. assert_eq!(render_point(0, 28, 128, 67, 12), 31); assert_eq!(render_point(12, 38, 128, 67, 46), 46); assert_eq!(render_point(0, 28, 12, 38, 4), 31); assert_eq!(render_point(4, 33, 12, 38, 8), 35); assert_eq!(render_point(12, 38, 46, 31, 16), 38); assert_eq!(render_point(16, 30, 46, 31, 23), 30); assert_eq!(render_point(23, 40, 46, 31, 33), 37); assert_eq!(render_point(46, 31, 128, 67, 70), 41); assert_eq!(render_point(0, 28, 4, 33, 2), 30); assert_eq!(render_point(4, 33, 8, 43, 6), 38); assert_eq!(render_point(8, 43, 12, 38, 10), 41); assert_eq!(render_point(12, 38, 16, 30, 14), 34); assert_eq!(render_point(16, 30, 23, 40, 19), 34); assert_eq!(render_point(23, 40, 33, 26, 28), 33); assert_eq!(render_point(33, 26, 46, 31, 39), 28); assert_eq!(render_point(46, 31, 70, 20, 58), 26); assert_eq!(render_point(70, 20, 128, 67, 90), 36); } fn floor_one_curve_compute_amplitude(floor1_y :&[u32], fl :&FloorTypeOne) -> (Vec, Vec) { let v = &[256, 128, 86, 64]; let range = v[(fl.floor1_multiplier - 1) as usize] as i32; let mut floor1_step2_flag = Vec::new(); floor1_step2_flag.push(true); floor1_step2_flag.push(true); let mut floor1_final_y = Vec::new(); floor1_final_y.push(floor1_y[0]); floor1_final_y.push(floor1_y[1]); for (i, el) in fl.floor1_x_list.iter().enumerate().skip(2) { let cur_low_neighbor = low_neighbor(&fl.floor1_x_list, i); let cur_high_neighbor = high_neighbor(&fl.floor1_x_list, i); let predicted = render_point( cur_low_neighbor.1, floor1_final_y[cur_low_neighbor.0], cur_high_neighbor.1, floor1_final_y[cur_high_neighbor.0], *el) as i32; let val = floor1_y[i] as i32; let highroom = range - predicted; let lowroom = predicted; let room = min(highroom, lowroom) * 2; if val > 0 { floor1_step2_flag[cur_low_neighbor.0] = true; floor1_step2_flag[cur_high_neighbor.0] = true; floor1_step2_flag.push(true); floor1_final_y.push(if val >= room { if highroom > lowroom { predicted + val - lowroom } else { predicted - val + highroom - 1 } } else { predicted + (if val % 2 == 1 { - val - 1 } else { val } >> 1) } as u32); } else { floor1_final_y.push(predicted as u32); floor1_step2_flag.push(false); } } // Clamp all entries of floor1_final_y to range for el in &mut floor1_final_y { *el = min(range as u32 - 1, *el); } return (floor1_final_y, floor1_step2_flag); } static FLOOR1_INVERSE_DB_TABLE :&[f32] = &[ 1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07, 1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07, 1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.1287530e-07, 2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07, 2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07, 3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07, 4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07, 6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07, 7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07, 1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06, 1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06, 1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06, 2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06, 2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06, 3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06, 4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06, 5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06, 7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06, 9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05, 1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05, 1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05, 2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05, 2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05, 3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05, 4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05, 5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05, 7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05, 9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824, 0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085, 0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536, 0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449, 0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787, 0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456, 0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927, 0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058, 0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457, 0.00092223983, 0.00098217216, 0.0010459992, 0.0011139742, 0.0011863665, 0.0012634633, 0.0013455702, 0.0014330129, 0.0015261382, 0.0016253153, 0.0017309374, 0.0018434235, 0.0019632195, 0.0020908006, 0.0022266726, 0.0023713743, 0.0025254795, 0.0026895994, 0.0028643847, 0.0030505286, 0.0032487691, 0.0034598925, 0.0036847358, 0.0039241906, 0.0041792066, 0.0044507950, 0.0047400328, 0.0050480668, 0.0053761186, 0.0057254891, 0.0060975636, 0.0064938176, 0.0069158225, 0.0073652516, 0.0078438871, 0.0083536271, 0.0088964928, 0.009474637, 0.010090352, 0.010746080, 0.011444421, 0.012188144, 0.012980198, 0.013823725, 0.014722068, 0.015678791, 0.016697687, 0.017782797, 0.018938423, 0.020169149, 0.021479854, 0.022875735, 0.024362330, 0.025945531, 0.027631618, 0.029427276, 0.031339626, 0.033376252, 0.035545228, 0.037855157, 0.040315199, 0.042935108, 0.045725273, 0.048696758, 0.051861348, 0.055231591, 0.058820850, 0.062643361, 0.066714279, 0.071049749, 0.075666962, 0.080584227, 0.085821044, 0.091398179, 0.097337747, 0.10366330, 0.11039993, 0.11757434, 0.12521498, 0.13335215, 0.14201813, 0.15124727, 0.16107617, 0.17154380, 0.18269168, 0.19456402, 0.20720788, 0.22067342, 0.23501402, 0.25028656, 0.26655159, 0.28387361, 0.30232132, 0.32196786, 0.34289114, 0.36517414, 0.38890521, 0.41417847, 0.44109412, 0.46975890, 0.50028648, 0.53279791, 0.56742212, 0.60429640, 0.64356699, 0.68538959, 0.72993007, 0.77736504, 0.82788260, 0.88168307, 0.9389798, 1.]; fn render_line(x0 :u32, y0 :u32, x1 :u32, y1 :u32, v :&mut Vec) { // TODO find out whether the type choices in this method are okay let dy = y1 as i32 - y0 as i32; let adx = x1 as i32 - x0 as i32; let ady = dy.abs(); let base = dy / adx; let mut y = y0 as i32; let mut err = 0; let sy = base + (if dy < 0 { -1 } else { 1 }); let ady = ady - base.abs() * adx; v.push(y as u32); for _ in (x0 + 1) .. x1 { err += ady; if err >= adx { err -= adx; y += sy; } else { y += base; } v.push(y as u32); } } fn floor_one_curve_synthesis(floor1_final_y :Vec, floor1_step2_flag :Vec, fl :&FloorTypeOne, n :u16) -> Vec { let floor1_final_y_s = |i :usize| { floor1_final_y[fl.floor1_x_list_sorted[i].0] }; let floor1_x_list_s = |i :usize| { fl.floor1_x_list_sorted[i].1 }; let floor1_step2_flag_s = |i :usize| { floor1_step2_flag[fl.floor1_x_list_sorted[i].0] }; let mut hx = 0; let mut lx = 0; let mut hy = 0; let mut floor = Vec::with_capacity(n as usize); let mut ly = floor1_final_y_s(0) * fl.floor1_multiplier as u32; for i in 1 .. fl.floor1_x_list.len() { if floor1_step2_flag_s(i) { hy = floor1_final_y_s(i) * fl.floor1_multiplier as u32; hx = floor1_x_list_s(i); render_line(lx, ly, hx, hy, &mut floor); lx = hx; ly = hy; } } if hx < n as u32 { render_line(hx, hy, n as u32, hy, &mut floor); } else if hx > n as u32 { floor.truncate(n as usize); } floor.into_iter() .map(|idx| FLOOR1_INVERSE_DB_TABLE[idx as usize]) .collect() } fn floor_decode<'a>(rdr :&mut BitpackCursor, ident :&IdentHeader, mapping :&Mapping, codebooks :&[Codebook], floors :&'a [Floor]) -> Result>, ()> { let mut decoded_floor_infos = Vec::with_capacity(ident.audio_channels as usize); for i in 0 .. ident.audio_channels as usize { let submap_number = mapping.mapping_mux[i] as usize; let floor_number = mapping.mapping_submap_floors[submap_number]; let floor = &floors[floor_number as usize]; use self::FloorSpecialCase::*; let floor_res = match floor { &Floor::TypeZero(ref fl) => { match floor_zero_decode(rdr, codebooks, fl) { Ok((coeff, amp)) => DecodedFloor::TypeZero(coeff, amp, fl), Err(Unused) => DecodedFloor::Unused, Err(PacketUndecodable) => try!(Err(())), } }, &Floor::TypeOne(ref fl) => { match floor_one_decode(rdr, codebooks, fl) { Ok(dfl) => DecodedFloor::TypeOne(dfl, fl), Err(Unused) => DecodedFloor::Unused, Err(PacketUndecodable) => try!(Err(())), } }, }; decoded_floor_infos.push(floor_res); } return Ok(decoded_floor_infos); } fn residue_packet_read_partition(rdr :&mut BitpackCursor, codebook :&Codebook, resid :&Residue, vec_v :&mut [f32]) -> Result<(), HuffmanVqReadErr> { if resid.residue_type == 0 { let codebook_dimensions = codebook.codebook_dimensions as usize; let step = resid.residue_partition_size as usize / codebook_dimensions; for i in 0 .. step { let entry_temp = try!(rdr.read_huffman_vq(codebook)); for (j, e) in entry_temp.iter().enumerate() { vec_v[i + j * step] += *e; } } } else { // Common for both format 1 and 2 let partition_size = resid.residue_partition_size as usize; let mut i = 0; while i < partition_size { let entries = try!(rdr.read_huffman_vq(codebook)); let vs = if let Some(vs) = vec_v.get_mut(i..(i + entries.len())) { vs } else { break; }; for (v, e) in vs.iter_mut().zip(entries.iter()) { *v += *e; } i += entries.len(); } } Ok(()) } fn residue_packet_decode_inner(rdr :&mut BitpackCursor, cur_blocksize :u16, do_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result, ()> { let ch = do_not_decode_flag.len(); let actual_size = (cur_blocksize / 2) as usize; // Older versions of the spec say max() here, // but there's been a bug in the spec. // It's been fixed since: // https://github.com/xiph/vorbis/pull/35 let limit_residue_begin = min(resid.residue_begin as usize, actual_size); let limit_residue_end = min(resid.residue_end as usize, actual_size); let cur_codebook = &codebooks[resid.residue_classbook as usize]; let classwords_per_codeword = cur_codebook.codebook_dimensions as usize; let n_to_read = limit_residue_end - limit_residue_begin; let partitions_to_read = n_to_read / resid.residue_partition_size as usize; let residue_classbok_ht = &cur_codebook.codebook_huffman_tree; // Allocate and zero all vectors that will be returned let mut vectors = vec![0.; ch * actual_size]; if n_to_read == 0 { // No residue to decode return Ok(vectors); } if classwords_per_codeword == 0 { // A value of 0 would create an infinite loop. // Therefore, throw an error in this case. try!(Err(())); } 'pseudo_return: loop { // ENdofpacketisnOrmal macro. Local replacement for try. macro_rules! eno { ($expr:expr) => (match $expr { $crate::std::result::Result::Ok(val) => val, $crate::std::result::Result::Err(_) => break 'pseudo_return, }) } let cl_stride :usize = partitions_to_read + classwords_per_codeword; let mut classifications = vec![0; ch as usize * cl_stride]; for pass in 0 .. 8 { let mut partition_count = 0; while partition_count < partitions_to_read { if pass == 0 { for (j, do_not_decode) in do_not_decode_flag.iter().enumerate() { if *do_not_decode { continue; } let mut temp = eno!(rdr.read_huffman(residue_classbok_ht)); for i in (0 .. classwords_per_codeword).rev() { classifications[j * cl_stride + i + partition_count] = temp % resid.residue_classifications as u32; temp = temp / resid.residue_classifications as u32; } } } for _ in 0 .. classwords_per_codeword { if partition_count >= partitions_to_read { break; } for (j, do_not_decode) in do_not_decode_flag.iter().enumerate() { if *do_not_decode { continue; } let offs = limit_residue_begin + partition_count * resid.residue_partition_size as usize; let vec_j_offs = &mut vectors[(j * actual_size + offs) .. ((j + 1) * actual_size)]; let vqclass = classifications[j * cl_stride + partition_count] as usize; let vqbook_opt = resid.residue_books[vqclass].get_val(pass); if let Some(vqbook) = vqbook_opt { let codebook = &codebooks[vqbook as usize]; // codebook is checked by header decode to have a value mapping // Decode the partition into output vector number j (vec_j). match residue_packet_read_partition(rdr, codebook, resid, vec_j_offs) { Ok(_) => (), Err(err) => { use ::header::HuffmanVqReadErr::*; match err { EndOfPacket => break 'pseudo_return, NoVqLookupForCodebook => panic!("Codebook must have a value mapping"), } }, } } } partition_count += 1; } } } break; } return Ok(vectors); } // Ok means "fine" (or end of packet, but thats "fine" too!), // Err means "not fine" -- the whole packet must be discarded fn residue_packet_decode(rdr :&mut BitpackCursor, cur_blocksize :u16, do_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result, ()> { let ch = do_not_decode_flag.len(); let vec_size = (cur_blocksize / 2) as usize; if resid.residue_type == 2 { let mut to_decode_found = false; for do_not_decode in do_not_decode_flag { if !do_not_decode { to_decode_found = true; break; } } if !to_decode_found { // Don't attempt to decode, but return vectors, // as required per spec only residue 2 has this. return Ok(vec![0.; ch * vec_size]); } else { // Construct a do_not_decode flag array let c_do_not_decode_flag = [false]; let vectors = try!(residue_packet_decode_inner(rdr, cur_blocksize * ch as u16, &c_do_not_decode_flag, resid, codebooks)); // Post decode step let mut vectors_deinterleaved = Vec::with_capacity(ch * vec_size); for j in 0 .. ch { let iter = vectors.chunks(ch).map(|chunk| chunk[j]); vectors_deinterleaved.extend(iter); } return Ok(vectors_deinterleaved); } } else { return residue_packet_decode_inner(rdr, cur_blocksize, do_not_decode_flag, resid, codebooks); } } #[inline] fn inverse_couple(m :f32, a :f32) -> (f32, f32) { if m > 0. { if a > 0. { (m, m - a) } else { (m + a, m) } } else { if a > 0. { (m, m + a) } else { (m - a, m) } } } // TODO this is probably slower than a replacement of // this function in unsafe code, no idea fn dual_mut_idx(v :&mut [T], idx_a :usize, idx_b :usize) -> (&mut T, &mut T) { assert_ne!(idx_a, idx_b, "not allowed, indices must be different!"); let range = if idx_a < idx_b { idx_a..idx_b+1 } else { idx_b..idx_a+1 }; let segment = &mut v[range]; let (first, rest) = segment.split_first_mut().unwrap(); let (last, _) = rest.split_last_mut().unwrap(); (first, last) } fn dct_iv_slow(buffer :&mut [f32]) { let x = buffer.to_vec(); let n = buffer.len(); let nmask = (n << 3) - 1; let mcos = (0 .. 8 * n) .map(|i| (std::f32::consts::FRAC_PI_4 * (i as f32) / (n as f32)).cos()) .collect::>(); for i in 0 .. n { let mut acc = 0.; for j in 0 .. n { acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask]; } buffer[i] = acc; } } #[allow(dead_code)] fn inverse_mdct_slow(buffer :&mut [f32]) { let n = buffer.len(); let n4 = n >> 2; let n2 = n >> 1; let n3_4 = n - n4; let mut temp = buffer[0 .. n2].to_vec(); dct_iv_slow(&mut temp); // returns -c'-d, a-b' for i in 0 .. n4 { buffer[i] = temp[i + n4]; // a-b' } for i in n4 .. n3_4 { buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d' } for i in n3_4 .. n { buffer[i] = -temp[i - n3_4]; // c'+d } } #[cfg(test)] #[test] fn test_imdct_slow() { use imdct_test::*; let mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1); inverse_mdct_slow(&mut arr_1); let mismatches = fuzzy_compare_array( &arr_1, &IMDCT_OUTPUT_TEST_ARR_1, 0.00005, true); let mismatches_limit = 0; if mismatches > mismatches_limit { panic!("Numer of mismatches {} was larger than limit of {}", mismatches, mismatches_limit); } } /// The right part of the previous window /// /// This is the only state that needs to be changed /// once the headers are read. pub struct PreviousWindowRight { data :Option>>, } impl PreviousWindowRight { /// Initialisation for new streams pub fn new() -> Self { return PreviousWindowRight{ data : None }; } /// If the state is still uninitialized pub fn is_empty(&self) -> bool { self.data.is_none() } } /** Returns the per-channel sample count of a packet if it were decoded. This operation is very cheap and doesn't involve actual decoding of the packet. Note: for the first packet in a stream, or in other instances when the `PreviousWindowRight` is reset, the decoding functions will return 0 samples for that packet, while this function returns a different number. Please use the `PreviousWindowRight::is_empty` function or other methods to check for this case. */ pub fn get_decoded_sample_count(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8]) -> Result { let mut rdr = BitpackCursor::new(packet); if try!(rdr.read_bit_flag()) { try!(Err(AudioReadError::AudioIsHeader)); } let mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1))); let mode = &setup.modes[mode_number as usize]; let bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 }; let n :u16 = 1 << bs; let previous_next_window_flag = if mode.mode_blockflag { Some((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag()))) } else { None }; // Compute windowing info for left window let window_center = n >> 1; let (left_win_start, _left_win_end, _left_n, _left_n_use_bs1) = if previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) { (0, window_center, n >> 1, mode.mode_blockflag) } else { let bs_0_exp = 1 << ident.blocksize_0; ((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false) }; // Compute windowing info for right window let (right_win_start, _right_win_end) = if previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) { (window_center, n) } else { let bs_0_exp = 1 << ident.blocksize_0; ((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2) }; Ok((right_win_start - left_win_start) as usize) } #[allow(unused_variables)] /** Main audio packet decoding function Pass your info to this function to get your raw packet data decoded. Panics if the passed PreviousWindowRight struct doesn't match the info from the ident header. */ pub fn read_audio_packet_generic(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight) -> Result { let mut rdr = BitpackCursor::new(packet); if try!(rdr.read_bit_flag()) { try!(Err(AudioReadError::AudioIsHeader)); } let mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1))); let mode = if let Some(mode) = setup.modes.get(mode_number as usize) { mode } else { try!(Err(AudioReadError::AudioBadFormat)) }; let mapping = &setup.mappings[mode.mode_mapping as usize]; let bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 }; let n :u16 = 1 << bs; let previous_next_window_flag = if mode.mode_blockflag { Some((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag()))) } else { None }; // Decode the floors let decoded_floor_infos = try!(floor_decode(&mut rdr, ident, mapping, &setup.codebooks, &setup.floors)); // Now calculate the no_residue vector let mut no_residue = TinyVec::<[bool; 32]>::new(); for fl in &decoded_floor_infos { no_residue.push(fl.is_unused()); } // and also propagate for (&mag, &angle) in mapping.mapping_magnitudes.iter().zip(mapping.mapping_angles.iter()) { if ! (no_residue[mag as usize] && no_residue[angle as usize]) { no_residue[mag as usize] = false; no_residue[angle as usize] = false; } } // Residue decode. let mut residue_vectors = vec![vec![]; mapping.mapping_mux.len()]; // Helper variable let resid_vec_len = (n / 2) as usize; for (i, &residue_number) in mapping.mapping_submap_residues.iter().enumerate() { let mut do_not_decode_flag = TinyVec::<[bool; 32]>::new(); for (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() { if mapping_mux_j as usize == i { do_not_decode_flag.push(no_residue[j]); } } let cur_residue = &setup.residues[residue_number as usize]; let vectors = match residue_packet_decode(&mut rdr, n, &do_not_decode_flag, cur_residue, &setup.codebooks) { Ok(v) => v, Err(_) => return Err(AudioReadError::AudioBadFormat), }; // The vectors Vec now contains the do_not_decode_flag.len() // many decoded residue vectors, each vector occupying n/2 scalars. let mut ch = 0; for (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() { if mapping_mux_j as usize == i { // TODO get rid of this copy somehow... let vec_at_ch = &vectors[resid_vec_len * ch .. resid_vec_len * (ch + 1)]; residue_vectors[j].clear(); residue_vectors[j].extend_from_slice(vec_at_ch); ch += 1; } } } record_residue_pre_inverse!(residue_vectors); // Inverse coupling for (&mag, &angle) in mapping.mapping_magnitudes.iter().rev().zip(mapping.mapping_angles.iter().rev()) { let (mag_vector, angle_vector) = dual_mut_idx(&mut residue_vectors, mag as usize, angle as usize); for (m, a) in mag_vector.iter_mut().zip(angle_vector.iter_mut()) { // https://github.com/rust-lang/rfcs/issues/372 // grumble grumble... let (new_m, new_a) = inverse_couple(*m, *a); *m = new_m; *a = new_a; } } record_residue_post_inverse!(residue_vectors); // Dot product let mut audio_spectri = Vec::with_capacity(ident.audio_channels as usize); for (residue_vector, chan_decoded_floor) in residue_vectors.iter().zip(decoded_floor_infos.iter()) { let mut floor_decoded :Vec = match chan_decoded_floor { &DecodedFloor::TypeZero(ref coefficients, amplitude, ref fl) => { floor_zero_compute_curve(coefficients, amplitude, fl, mode.mode_blockflag, n / 2) }, &DecodedFloor::TypeOne(ref floor_y, ref fl) => { let (floor1_final_y, floor1_step2_flag) = floor_one_curve_compute_amplitude(floor_y, fl); floor_one_curve_synthesis(floor1_final_y, floor1_step2_flag, fl, n / 2) }, &DecodedFloor::Unused => { // Generate zero'd floor of length n/2 vec![0.; (n / 2) as usize] }, }; // The only legal length is n/2. // The implementation should ensure this, // but its good for debugging to have this // confirmed. debug_assert_eq!(residue_vector.len(), (n / 2) as usize); debug_assert_eq!(floor_decoded.len(), (n / 2) as usize); // Now do the multiplication for (fl_sc, r_sc) in floor_decoded.iter_mut().zip(residue_vector.iter()) { *fl_sc *= *r_sc; } audio_spectri.push(floor_decoded); } record_pre_mdct!(audio_spectri); // Inverse MDCT for ref mut spectrum in audio_spectri.iter_mut() { let size = (n / 2) as usize; let ext = iter::repeat(0.).take(size); spectrum.extend(ext); let cached_bd = &ident.cached_bs_derived[mode.mode_blockflag as usize]; //imdct::inverse_mdct_naive(cached_bd, &mut spectrum[..]); imdct::inverse_mdct(cached_bd, &mut spectrum[..], bs); //inverse_mdct_slow(&mut spectrum[..]); } record_post_mdct!(audio_spectri); // Compute windowing info for left window let window_center = n >> 1; let (left_win_start, left_win_end, left_n, left_n_use_bs1) = if previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) { (0, window_center, n >> 1, mode.mode_blockflag) } else { let bs_0_exp = 1 << ident.blocksize_0; ((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false) }; // Compute windowing info for right window let (right_win_start, right_win_end) = if previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) { (window_center, n) } else { let bs_0_exp = 1 << ident.blocksize_0; ((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2) }; /*println!("n={} prev_win_flag={:?} left_win_(start={}, end={}, n={}) right_win(start={}, end={})", n, previous_next_window_flag, left_win_start, left_win_end, left_n, right_win_start, right_win_end); // */ // Overlap add and store last half // in PreviousWindowRight // Only add if prev has elements. let mut future_prev_halves = Vec::with_capacity(ident.audio_channels as usize); if let Some(prev_data) = pwr.data.take() { // TODO maybe check if prev_n matches blocksize_0 or blocksize_1, // and the channel number. Panic if no match of either. assert_eq!(audio_spectri.len(), prev_data.len()); let win_slope = &ident.cached_bs_derived[left_n_use_bs1 as usize].window_slope; for (prev_chan, chan) in prev_data.into_iter().zip(audio_spectri.iter_mut()) { let plen = prev_chan.len(); let left_win_start = left_win_start as usize; let right_win_start = right_win_start as usize; let right_win_end = right_win_end as usize; // Then do the actual overlap_add // Set up iterators for all the variables let range = { let start = left_win_start; let end = left_win_start + plen; start..end }; let prev = prev_chan[0..plen].iter(); let (lhs, rhs) = { if win_slope.len() < plen { // According to fuzzing, code can trigger this case, // so let's error gracefully instead of panicing. try!(Err(AudioReadError::AudioBadFormat)); } let win_slope = &win_slope[0..plen]; (win_slope.iter(), win_slope.iter().rev()) }; for (((v, lhs), prev), rhs) in chan[range].iter_mut().zip(lhs).zip(prev).zip(rhs) { *v = (*v * lhs) + (prev * rhs); } // and populate the future previous half let future_prev_half = chan[right_win_start..right_win_end].into(); future_prev_halves.push(future_prev_half); // Remove everything left of the left window start, // by moving the the stuff right to it to the left. if left_win_start > 0 { for i in 0 .. right_win_start - left_win_start { chan[i] = chan[i + left_win_start]; } } // Now the last step: truncate the decoded packet // to cut off the right part. chan.truncate(right_win_start - left_win_start); // TODO stb_vorbis doesn't use right_win_start // in the calculation above but sth like // if len < right_win_start { len } else { right_win_start } } } else { for chan in audio_spectri.iter_mut() { let mut future_prev_half = Vec::with_capacity( (right_win_end - right_win_start) as usize); for i in right_win_start as usize .. right_win_end as usize { future_prev_half.push(chan[i]); } future_prev_halves.push(future_prev_half); // If there is no previous window right, we have to discard // the whole packet. chan.truncate(0); } } pwr.data = Some(future_prev_halves); // Generate final integer samples let final_i16_samples = S::from_floats(audio_spectri); Ok(final_i16_samples) } /** Main audio packet decoding function Pass your info to this function to get your raw packet data decoded. Panics if the passed PreviousWindowRight struct doesn't match the info from the ident header. */ pub fn read_audio_packet(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight) -> Result>, AudioReadError> { read_audio_packet_generic(ident, setup, packet, pwr) } lewton-0.10.2/src/bitpacking.rs010066400017500001750000000502261367240530400145460ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Vorbis bitpacking layer Functionality to read content from the bitpacking layer. Implements vorbis spec, section 2. The most important struct of this mod is the `BitpackCursor` struct. It can be instantiated using `BitpackCursor::new()`. Note that this implementation doesn't fully align with the spec in the regard that it assumes a byte is an octet. This is no problem on most architectures. This non-alignment to the spec is due to the fact that the rust language is highly leaned towards byte == u8, and doesn't even have a builtin single byte type. */ use ::huffman_tree::{VorbisHuffmanTree, PeekedDataLookupResult}; /// A Cursor on slices to read numbers and bitflags, bit aligned. pub struct BitpackCursor <'a> { bit_cursor :u8, byte_cursor :usize, inner :&'a[u8], } macro_rules! sign_extend { ( $num:expr, $desttype:ident, $bit_cnt_large:expr, $bit_cnt_small:expr) => { { let n = $num; let res :$desttype = n as $desttype; let k :u8 = $bit_cnt_large - $bit_cnt_small; res << k >> k } } } #[test] fn test_sign_extend() { assert_eq!(sign_extend!(0b00, i8, 8, 2), 0); assert_eq!(sign_extend!(0b01, i8, 8, 2), 1); assert_eq!(sign_extend!(0b11, i8, 8, 2), -1); assert_eq!(sign_extend!(0b111, i8, 8, 3), -1); assert_eq!(sign_extend!(0b101, i8, 8, 3), -3); assert_eq!(sign_extend!(0b01111110, i16, 16, 8), 126); assert_eq!(sign_extend!(0b10000010, i16, 16, 8), -126); } /// Returns `num` bits of 1 (but never more than 8). fn mask_bits(num : u8) -> u8 { !((!0u8).wrapping_shl(num as u32)) | if num >= 8 { 0xff } else { 0 } } // Same as mask_bits but different in a special case: for num % 8 == 0 // Make sure that 0 <= num <= 8. fn bmask_bits(num : u8) -> u8 { (!0u8).wrapping_shr(8 - num as u32) } #[test] fn test_mask_bits() { assert_eq!(mask_bits(0), 0b00000000); assert_eq!(mask_bits(1), 0b00000001); assert_eq!(mask_bits(2), 0b00000011); assert_eq!(mask_bits(3), 0b00000111); assert_eq!(mask_bits(4), 0b00001111); assert_eq!(mask_bits(5), 0b00011111); assert_eq!(mask_bits(6), 0b00111111); assert_eq!(mask_bits(7), 0b01111111); assert_eq!(mask_bits(8), 0b11111111); } #[test] fn test_bmask_bits() { assert_eq!(bmask_bits(0), 0b11111111); assert_eq!(bmask_bits(1), 0b00000001); assert_eq!(bmask_bits(2), 0b00000011); assert_eq!(bmask_bits(3), 0b00000111); assert_eq!(bmask_bits(4), 0b00001111); assert_eq!(bmask_bits(5), 0b00011111); assert_eq!(bmask_bits(6), 0b00111111); assert_eq!(bmask_bits(7), 0b01111111); assert_eq!(bmask_bits(8), 0b11111111); } // The main macro to read bit aligned // Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down) macro_rules! bpc_read_body { ( $rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr ) => { { let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize; let octetnum_rounded_up :usize = last_octet_partial + $octetnum; let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8; if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up { /*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)", $bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial); println!(" byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */ /*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum, $selfarg.byte_cursor, $selfarg.bit_cursor, &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + 1 + octetnum_rounded_up]);// */ if $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() { //println!(" => Out of bounds :\\"); return Err(()); } let buf = &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + 1 + octetnum_rounded_up]; let mut res :$rettype = buf[0] as $rettype; res >>= $selfarg.bit_cursor; let mut cur_bit_cursor = 8 - $selfarg.bit_cursor; for i in 1 .. octetnum_rounded_up { res |= (buf[i] as $rettype) << cur_bit_cursor; cur_bit_cursor += 8; } let last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after); res |= (last_bits as $rettype) << cur_bit_cursor; $selfarg.byte_cursor += octetnum_rounded_up; $selfarg.bit_cursor = bit_cursor_after; //println!(" => {:?}", res); Ok(res) } else { /*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={})", $bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial); println!(" byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */ /*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum, $selfarg.byte_cursor, $selfarg.bit_cursor, &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + octetnum_rounded_up]);// */ if $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() { //println!(" => Out of bounds :\\"); return Err(()); } let buf = &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + octetnum_rounded_up]; let mut res :$rettype = buf[0] as $rettype; res >>= $selfarg.bit_cursor; if $bitnum <= 8 { res &= mask_bits($bitnum) as $rettype; } let mut cur_bit_cursor = 8 - $selfarg.bit_cursor; for i in 1 .. octetnum_rounded_up - 1 { res |= (buf[i] as $rettype) << cur_bit_cursor; cur_bit_cursor += 8; } if $bitnum > 8 { let last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after); res |= (last_bits as $rettype) << cur_bit_cursor; } $selfarg.byte_cursor += $octetnum; $selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize; $selfarg.bit_cursor = bit_cursor_after; //println!(" => {:?}", res); Ok(res) } } } } // The main macro to peek bit aligned // Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down) macro_rules! bpc_peek_body { ( $rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr ) => { { let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize; let octetnum_rounded_up :usize = last_octet_partial + $octetnum; let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8; if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up { /*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)", $bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial); println!(" byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */ /*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum, $selfarg.byte_cursor, $selfarg.bit_cursor, &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + 1 + octetnum_rounded_up]);// */ if $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() { //println!(" => Out of bounds :\\"); return Err(()); } let buf = &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + 1 + octetnum_rounded_up]; let mut res :$rettype = buf[0] as $rettype; res >>= $selfarg.bit_cursor; let mut cur_bit_cursor = 8 - $selfarg.bit_cursor; for i in 1 .. octetnum_rounded_up { res |= (buf[i] as $rettype) << cur_bit_cursor; cur_bit_cursor += 8; } let last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after); res |= (last_bits as $rettype) << cur_bit_cursor; //println!(" => {:?}", res); Ok(res) } else { /*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={})", $bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial); println!(" byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */ /*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum, $selfarg.byte_cursor, $selfarg.bit_cursor, &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + octetnum_rounded_up]);// */ if $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() { //println!(" => Out of bounds :\\"); return Err(()); } let buf = &$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor + octetnum_rounded_up]; let mut res :$rettype = buf[0] as $rettype; res >>= $selfarg.bit_cursor; if $bitnum <= 8 { res &= mask_bits($bitnum) as $rettype; } let mut cur_bit_cursor = 8 - $selfarg.bit_cursor; for i in 1 .. octetnum_rounded_up - 1 { res |= (buf[i] as $rettype) << cur_bit_cursor; cur_bit_cursor += 8; } if $bitnum > 8 { let last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after); res |= (last_bits as $rettype) << cur_bit_cursor; } //println!(" => {:?}", res); Ok(res) } } } } // The main macro to advance bit aligned // Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down) macro_rules! bpc_advance_body { ( $bitnum:expr, $octetnum:expr, $selfarg:expr ) => { { let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize; let octetnum_rounded_up :usize = last_octet_partial + $octetnum; let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8; if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up { $selfarg.byte_cursor += octetnum_rounded_up; $selfarg.bit_cursor = bit_cursor_after; //println!(" => {:?}", res); Ok(()) } else { $selfarg.byte_cursor += $octetnum; $selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize; $selfarg.bit_cursor = bit_cursor_after; //println!(" => {:?}", res); Ok(()) } } } } macro_rules! uk_reader { ( $fnname:ident, $rettype:ident, $bitnum:expr, $octetnum:expr) => { #[inline] pub fn $fnname(&mut self) -> Result<$rettype, ()> { bpc_read_body!($rettype, $bitnum, $octetnum, self) } } } macro_rules! ik_reader { ( $fnname:ident, $rettype:ident, $bitnum_of_rettype:expr, $bitnum:expr, $octetnum:expr) => { #[inline] pub fn $fnname(&mut self) -> Result<$rettype, ()> { Ok(sign_extend!(try!( bpc_read_body!($rettype, $bitnum, $octetnum, self)), $rettype, $bitnum_of_rettype, $bitnum)) } } } macro_rules! ik_dynamic_reader { ( $fnname:ident, $rettype:ident, $bitnum_of_rettype:expr) => { #[inline] pub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> { let octet_num :usize = (bit_num / 8) as usize; assert!(bit_num <= $bitnum_of_rettype); Ok(sign_extend!(try!( bpc_read_body!($rettype, bit_num, octet_num, self)), $rettype, $bitnum_of_rettype, bit_num)) } } } macro_rules! uk_dynamic_reader { ( $fnname:ident, $rettype:ident, $bit_num_max:expr) => { #[inline] pub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> { let octet_num :usize = (bit_num / 8) as usize; if bit_num == 0 { // TODO: one day let bpc_read_body handle this, // if its smartly doable in there. // For why it is required, see comment in the // test_bitpacking_reader_empty function. return Ok(0); } assert!(bit_num <= $bit_num_max); bpc_read_body!($rettype, bit_num, octet_num, self) } } } fn float32_unpack(val :u32) -> f32 { let sgn = val & 0x80000000; let exp = (val & 0x7fe00000) >> 21; let mantissa = (val & 0x1fffff) as f64; let signed_mantissa = if sgn != 0 { -mantissa } else { mantissa }; return signed_mantissa as f32 * (exp as f32 - 788.0).exp2(); } #[test] fn test_float_32_unpack() { // Values were printed out from what stb_vorbis // calculated for this function from a test file. assert_eq!(float32_unpack(1611661312), 1.000000); assert_eq!(float32_unpack(1616117760), 5.000000); assert_eq!(float32_unpack(1618345984), 11.000000); assert_eq!(float32_unpack(1620115456), 17.000000); assert_eq!(float32_unpack(1627381760), 255.000000); assert_eq!(float32_unpack(3759144960), -1.000000); assert_eq!(float32_unpack(3761242112), -2.000000); assert_eq!(float32_unpack(3763339264), -4.000000); assert_eq!(float32_unpack(3763601408), -5.000000); assert_eq!(float32_unpack(3765436416), -8.000000); assert_eq!(float32_unpack(3765829632), -11.000000); assert_eq!(float32_unpack(3768451072), -30.000000); assert_eq!(float32_unpack(3772628992), -119.000000); assert_eq!(float32_unpack(3780634624), -1530.000000); } #[test] fn test_float_32_unpack_issue_24() { // Regression test for issue #24, a // mismatch in decoded output for audio_simple_with_error.ogg // and singlemap-test.ogg. // The values are taken from the codebook_delta_value and // codebook_minimum_value values of the singlemap-test.ogg file. // The expected values come from stb_vorbis. assert_eq!(float32_unpack(1628434432), 255.0); assert_eq!(float32_unpack(1621655552), 17.0); assert_eq!(float32_unpack(1619722240), 11.0); assert_eq!(float32_unpack(1613234176), 1.0); assert_eq!(float32_unpack(3760717824), -1.0); assert_eq!(float32_unpack(3762814976), -2.0); assert_eq!(float32_unpack(3764912128), -4.0); assert_eq!(float32_unpack(3765043200), -5.0); assert_eq!(float32_unpack(3767009280), -8.0); assert_eq!(float32_unpack(3767205888), -11.0); assert_eq!(float32_unpack(3769565184), -30.0); assert_eq!(float32_unpack(3773751296), -119.0); assert_eq!(float32_unpack(3781948416), -1530.0); } // allow some code that is only used in the tests #[allow(dead_code)] impl <'a> BitpackCursor <'a> { /// Creates a new `BitpackCursor` for the given data array pub fn new(arr : &'a[u8]) -> BitpackCursor { return BitpackCursor::<'a> { bit_cursor: 0, byte_cursor: 0, inner: arr }; } // Unsigned, non-dynamic reader methods // u32 based // TODO add here if needed uk_reader!(read_u32, u32, 32, 4); // TODO add here if needed uk_reader!(read_u24, u32, 24, 3); // TODO add here if needed // u16 based uk_reader!(read_u16, u16, 16, 2); // TODO add here if needed uk_reader!(read_u13, u16, 13, 1); // TODO add here if needed // u8 based uk_reader!(read_u8, u8, 8, 1); uk_reader!(read_u7, u8, 7, 0); uk_reader!(read_u6, u8, 6, 0); uk_reader!(read_u5, u8, 5, 0); uk_reader!(read_u4, u8, 4, 0); uk_reader!(read_u3, u8, 3, 0); uk_reader!(read_u2, u8, 2, 0); uk_reader!(read_u1, u8, 1, 0); // Returning bool: #[inline] pub fn read_bit_flag(&mut self) -> Result { return Ok(try!(self.read_u1()) == 1); } // Unsigned dynamic reader methods // They panic if you give them invalid params // (bit_num larger than maximum allowed bit number for the type) uk_dynamic_reader!(read_dyn_u8, u8, 8); uk_dynamic_reader!(read_dyn_u16, u16, 16); uk_dynamic_reader!(read_dyn_u32, u32, 32); uk_dynamic_reader!(read_dyn_u64, u64, 64); // Signed non-dynamic reader methods ik_reader!(read_i32, i32, 32, 32, 4); // TODO add here if needed ik_reader!(read_i8, i8, 8, 8, 1); ik_reader!(read_i7, i8, 8, 7, 0); // TODO add here if needed // Signed dynamic reader methods // They panic if you give them invalid params // (bit_num larger than maximum allowed bit number for the type) ik_dynamic_reader!(read_dyn_i8, i8, 8); ik_dynamic_reader!(read_dyn_i16, i16, 16); ik_dynamic_reader!(read_dyn_i32, i32, 32); // Float reading methods /// Reads a single floating point number in the vorbis-float32 format pub fn read_f32(&mut self) -> Result { let val = try!(self.read_u32()); Ok(float32_unpack(val)) } /// Peeks 8 bits of non read yet content without advancing the reader #[inline] pub fn peek_u8(&self) -> Result { bpc_peek_body!(u8, 8, 1, self) } // Advances the reader by the given number of bits (up to 8). pub fn advance_dyn_u8(&mut self, bit_num :u8) -> Result<(), ()> { let octet_num :usize = (bit_num / 8) as usize; if bit_num == 0 { // TODO: one day let bpc_advance_body handle this, // if its smartly doable in there. // For why it is required, see comment in the // test_bitpacking_reader_empty function. return Ok(()); } assert!(bit_num <= 8); bpc_advance_body!(bit_num, octet_num, self) } /// Reads a huffman word using the codebook abstraction pub fn read_huffman(&mut self, tree :&VorbisHuffmanTree) -> Result { //let mut c :usize = 0; //let mut w :usize = 0; let mut iter = match self.peek_u8() { Ok(data) => match tree.lookup_peeked_data(8, data as u32) { PeekedDataLookupResult::Iter(advance, iter) => { try!(self.advance_dyn_u8(advance)); iter }, PeekedDataLookupResult::PayloadFound(advance, payload) => { try!(self.advance_dyn_u8(advance)); return Ok(payload); }, }, Err(_) => tree.iter(), }; loop { let b = try!(self.read_bit_flag()); /* c +=1; w >>= 1; w |= (b as usize) << 63; // Put this into the Some arm of the match below in order to debug: {print!("({}:{}:{}) ", w >> (64 - c), v, c); } // */ match iter.next(b) { Some(v) => return Ok(v), None => (), } } } } #[test] fn test_bitpacking_reader_static() { // Test vectors taken from Vorbis I spec, section 2.1.6 let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_u4().unwrap(), 12); assert_eq!(cur.read_u3().unwrap(), 7); assert_eq!(cur.read_u7().unwrap(), 17); assert_eq!(cur.read_u13().unwrap(), 6969); } #[test] fn test_bitpacking_reader_dynamic() { // Test vectors taken from Vorbis I spec, section 2.1.6 let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_dyn_u8(4).unwrap(), 12); assert_eq!(cur.read_dyn_u8(3).unwrap(), 7); assert_eq!(cur.read_dyn_u16(7).unwrap(), 17); assert_eq!(cur.read_dyn_u16(13).unwrap(), 6969); // Regression test for bug let test_arr = &[93, 92]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_dyn_u32(10).unwrap(), 93); } #[test] fn test_bitpacking_reader_empty() { // Same as the normal bitpacking test // but with some additional empty reads. // // This is expected to happen by the vorbis spec. // For example, the mode_number read in the audio packet // decode at first position may be 0 bit long (if there // is only one mode, ilog([vorbis_mode_count] - 1) is zero). let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_dyn_u8(4).unwrap(), 12); assert_eq!(cur.read_dyn_u8(0).unwrap(), 0); assert_eq!(cur.read_dyn_u8(0).unwrap(), 0); assert_eq!(cur.read_dyn_u8(3).unwrap(), 7); assert_eq!(cur.read_dyn_u8(0).unwrap(), 0); assert_eq!(cur.read_dyn_u16(7).unwrap(), 17); assert_eq!(cur.read_dyn_u16(0).unwrap(), 0); assert_eq!(cur.read_dyn_u16(0).unwrap(), 0); assert_eq!(cur.read_dyn_u16(13).unwrap(), 6969); assert_eq!(cur.read_dyn_u16(0).unwrap(), 0); } #[test] fn test_bitpacking_reader_byte_aligned() { // Check that bitpacking readers work with "normal" byte aligned types: let test_arr = &[0x00, 0x00, 0x00, 0x00, 0x01]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_dyn_u32(32).unwrap(), 0); assert_eq!(cur.read_dyn_u8(8).unwrap(), 1); // We not just check here whether it works for byte aligned // "normal" (non-dynamic) reader methods, we also check // whether, after reading first one, then seven bits, // it "gets back" to byte alignment (and increases the byte ctr) let test_arr = &[0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01]; let mut cur = BitpackCursor::new(test_arr); assert_eq!(cur.read_u1().unwrap(), 1); assert_eq!(cur.read_u7().unwrap(), 4); assert_eq!(cur.read_i8().unwrap(), 2); assert_eq!(cur.read_u32().unwrap(), 0); assert_eq!(cur.read_u8().unwrap(), 1); } #[test] fn test_capture_pattern_nonaligned() { // Regression test from test OGG file // Tests for proper codebook capture // pattern reading. // // The OGG vorbis capture pattern // is a three octet (24 bits) value. // // The first block tests capture pattern // reading in a byte aligned scenario. // The actually problematic part was // the second block: it tests capture // pattern reading in a non-aligned // situation. let capture_pattern_arr = &[0x42, 0x43, 0x56]; let mut cur = BitpackCursor::new(capture_pattern_arr); assert_eq!(cur.read_u24().unwrap(), 0x564342); let test_arr = &[0x28, 0x81, 0xd0, 0x90, 0x55, 0x00, 0x00]; let mut cur = BitpackCursor::new(test_arr); cur.read_u5().unwrap(); // some value we are not interested in cur.read_u5().unwrap(); // some value we are not interested in assert_eq!(cur.read_u4().unwrap(), 0); assert_eq!(cur.read_u24().unwrap(), 0x564342); // Ensure that we incremented by only three bytes, not four assert_eq!(cur.read_u16().unwrap(), 1); } lewton-0.10.2/src/capi.rs010066400017500001750000000077361367355157400133730ustar 00000000000000use std::os::raw::c_int; use std::slice::from_raw_parts; use std::ptr::null_mut; use ::header::{read_header_setup, //read_header_comment, read_header_ident, IdentHeader, //CommentHeader, SetupHeader}; use ::audio::{PreviousWindowRight, read_audio_packet_generic}; /// Main Decoder State /// /// It is created by `lewton_context_from_extradata` by passing a xiph-laced extradate bundle pub struct LewtonContext { pwr :PreviousWindowRight, ident_hdr :IdentHeader, //comment_hdr :CommentHeader, setup_hdr :SetupHeader, } fn read_xiph_lacing(arr :&mut &[u8]) -> Option { let mut r = 0; loop { if arr.len() == 0 { return None; } let v = arr[0] as u64; *arr = &arr[1..]; r += v; if v < 255 { return Some(r); } } } impl LewtonContext { fn from_extradata(mut extradata :&[u8]) -> Option { // We must start with a 2 as per matroska encapsulation spec if extradata.len() == 0 || extradata[0] != 2 { return None } extradata = &extradata[1..]; let ident_len = read_xiph_lacing(&mut extradata)? as usize; let comment_len = read_xiph_lacing(&mut extradata)? as usize; let ident_hdr = read_header_ident(&extradata[0..ident_len]).ok()?; extradata = &extradata[ident_len..]; //let comment_hdr = read_header_comment(&extradata[0..comment_len]).ok()?; extradata = &extradata[comment_len..]; let setup_hdr = read_header_setup(extradata, ident_hdr.audio_channels, (ident_hdr.blocksize_0, ident_hdr.blocksize_1)) .ok()?; Some(LewtonContext { pwr : PreviousWindowRight::new(), ident_hdr, //comment_hdr, setup_hdr, }) } } /// A multichannel vector of samples /// /// It is produced by `lewton_decode_packet` /// /// Use `lewton_samples_count` to retrieve the number of samples available in each channel /// Use `lewton_samples_channels` to retrieve the number of channels /// Use `lewton_samples_for_channel_f32` to retrieve a reference to the data present in the /// channel /// /// use `lewton_samples_drop()` to deallocate the memory pub struct LewtonSamples(Vec>); /// Create a LewtonContext from an extradata buffer /// /// Returns either NULL or a newly allocated LewtonContext #[no_mangle] pub unsafe extern fn lewton_context_from_extradata( data :*const u8, len :usize) -> *mut LewtonContext { if data.is_null() { return null_mut(); } let extradata = from_raw_parts(data, len); if let Some(cx) = LewtonContext::from_extradata(extradata) { let boxed = Box::new(cx); Box::into_raw(boxed) } else { null_mut() } } /// Reset the Decoder to support seeking. #[no_mangle] pub unsafe extern fn lewton_context_reset(ctx :*mut LewtonContext) { (*ctx).pwr = PreviousWindowRight::new(); } /// Decode a packet to LewtonSamples when possible /// /// Returns 0 on success, non-zero if no samples can be produced #[no_mangle] pub unsafe extern fn lewton_decode_packet(ctx :*mut LewtonContext, pkt :*const u8, len: usize, sample_out :*mut *mut LewtonSamples) -> c_int { if pkt.is_null() || ctx.is_null() || sample_out.is_null() { return 1; } let pkt = from_raw_parts(pkt, len); let decoded = read_audio_packet_generic(&(*ctx).ident_hdr, &(*ctx).setup_hdr, &pkt, &mut (*ctx).pwr); let decoded = if let Ok(v) = decoded { v } else { return 2; }; let boxed = Box::new(LewtonSamples(decoded)); *sample_out = Box::into_raw(boxed); return 0; } /// Provide the number of samples present in each channel #[no_mangle] pub unsafe extern fn lewton_samples_count(samples :*const LewtonSamples) -> usize { (*samples).0 .get(0) .map(|v| v.len()) .unwrap_or(0) } /// Provide a reference to the channel sample data pub unsafe extern fn lewton_samples_f32(samples :*const LewtonSamples, channel :usize) -> *const f32 { (*samples).0 .get(channel) .map(|v| v.as_ptr()) .unwrap_or(std::ptr::null()) } #[no_mangle] pub unsafe extern fn lewton_samples_drop(samples :*mut LewtonSamples) { std::mem::drop(Box::from_raw(samples)); } #[no_mangle] pub unsafe extern fn lewton_context_drop(ctx :*mut LewtonContext) { std::mem::drop(Box::from_raw(ctx)); } lewton-0.10.2/src/header.rs010066400017500001750000001123231376463522500136710ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Header decoding This module takes care of decoding of the three vorbis headers: 1. Identification 2. Comment 3. Setup It builds only on the internal bitpacking layer and the internal huffman tree handling mod. Everything else about the headers is decoded in this mod. */ use std::error; use std::fmt; use ::bitpacking::BitpackCursor; use ::huffman_tree::{VorbisHuffmanTree, HuffmanError}; use std::io::{Cursor, ErrorKind, Read, Error}; use byteorder::{ReadBytesExt, LittleEndian}; use std::string::FromUtf8Error; use header_cached::{CachedBlocksizeDerived, compute_bark_map_cos_omega}; /// Errors that can occur during Header decoding #[derive(Debug)] #[derive(PartialEq)] pub enum HeaderReadError { EndOfPacket, /// If the passed data don't start with the "vorbis" /// capture pattern, this error is returned. NotVorbisHeader, UnsupportedVorbisVersion, /// If the header violates the vorbis spec HeaderBadFormat, /// The given packet indeed seems to be a vorbis header, /// but it looks like it is a different header type than /// the function it was passed to. /// /// It is not guaranteed that the type is a valid header type. HeaderBadType(u8), /// The given packet does not seem to be a header as per vorbis spec, /// instead it seems to be an audio packet. HeaderIsAudio, Utf8DecodeError, /// If the needed memory isn't addressable by us /// /// This error is returned if a calculation yielded a higher value for /// an internal buffer size that doesn't fit into the platform's address range. /// Note that if we "simply" encounter an allocation failure (OOM, etc), /// we do what libstd does in these cases: crash. /// /// This error is not automatically an error of the passed data, /// but rather is due to insufficient decoder hardware. BufferNotAddressable, } // For the () error type returned by the bitpacking layer // TODO that type choice was a bit unfortunate, // perhaps one day fix this impl From<()> for HeaderReadError { fn from(_ :()) -> HeaderReadError { HeaderReadError::EndOfPacket } } impl From for HeaderReadError { fn from(_ :HuffmanError) -> HeaderReadError { HeaderReadError::HeaderBadFormat } } impl From for HeaderReadError { fn from(err :Error) -> HeaderReadError { match err.kind() { ErrorKind::UnexpectedEof => HeaderReadError::EndOfPacket, _ => panic!("Non EOF Error occured when reading from Cursor<&[u8]>: {}", err), } } } impl From for HeaderReadError { fn from(_ :FromUtf8Error) -> HeaderReadError { HeaderReadError::Utf8DecodeError } } impl error::Error for HeaderReadError {} impl fmt::Display for HeaderReadError { fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { let description = match self { HeaderReadError::EndOfPacket => "End of packet reached.", HeaderReadError::NotVorbisHeader => "The packet is not a vorbis header", HeaderReadError::UnsupportedVorbisVersion => "The vorbis version is not supported", HeaderReadError::HeaderBadFormat => "Invalid header", HeaderReadError::HeaderBadType(_) => "Invalid/unexpected header type", HeaderReadError::HeaderIsAudio => "Packet seems to be audio", HeaderReadError::Utf8DecodeError => "UTF-8 decoding error", HeaderReadError::BufferNotAddressable => "Requested to create buffer of non-addressable size", }; write!(fmt, "{}", description) } } /// Macro to convert values of any unsigned integral non-usize type to /// usize, and then check whether there had been any losses due to conversion. /// /// If there were, it will return the BufferNotAddressable error. macro_rules! convert_to_usize { ( $val:expr, $val_type:ident ) => { { let converted :usize = $val as usize; if $val != converted as $val_type { try!(Err(HeaderReadError::BufferNotAddressable)); } converted }} } // Internal function, tries to find out whether the // data returned by rdr belong to a vorbis header // On success it returns Some(n) with n as packet type // (you must check that n from 1,3,5) macro_rules! read_header_begin_body { ( $rdr:expr ) => { { let res = try!($rdr.read_u8()); if res & 1 == 0 { // This is an audio packet per vorbis spec, if anything. // (audio packets have their first bit set to 0, // header packets have it set to 1) try!(Err(HeaderReadError::HeaderIsAudio)); } let is_vorbis = try!($rdr.read_u8()) == 0x76 && // 'v' try!($rdr.read_u8()) == 0x6f && // 'o' try!($rdr.read_u8()) == 0x72 && // 'r' try!($rdr.read_u8()) == 0x62 && // 'b' try!($rdr.read_u8()) == 0x69 && // 'i' try!($rdr.read_u8()) == 0x73; // 's' if !is_vorbis { try!(Err(HeaderReadError::NotVorbisHeader)); } return Ok(res); }} } fn read_header_begin(rdr :&mut BitpackCursor) -> Result { read_header_begin_body!(rdr) } fn read_header_begin_cursor(rdr :&mut Cursor<&[u8]>) -> Result { read_header_begin_body!(rdr) } #[test] fn test_read_hdr_begin() { // Only tests flawed header begins, correct headers // are tested later by the test methods for the headers // Flawed ident header (see char before the /**/) let test_arr = &[0x01, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x72, /**/ 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xb5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01]; let mut rdr :BitpackCursor = BitpackCursor::new(test_arr); assert_eq!(read_header_begin(&mut rdr), Err(HeaderReadError::NotVorbisHeader)); } /// The set of the three Vorbis headers pub type HeaderSet = (IdentHeader, CommentHeader, SetupHeader); /** Representation for the identification header The identification header is the first of the three headers inside each vorbis stream. It covers basic information about the stream. */ pub struct IdentHeader { /// The number of audio channels in the stream pub audio_channels :u8, /// The sample rate of the stream pub audio_sample_rate :u32, /// The maximum bit rate of the stream /// /// Note that this value is only a hint /// and may be off by a large amount. pub bitrate_maximum :i32, /// The nominal bit rate of the stream /// /// Note that this value is only a hint /// and may be off by a large amount. pub bitrate_nominal :i32, /// The minimum bit rate of the stream /// /// Note that this value is only a hint /// and may be off by a large amount. pub bitrate_minimum :i32, pub blocksize_0 :u8, pub blocksize_1 :u8, pub(crate) cached_bs_derived :[CachedBlocksizeDerived; 2], } /** Reading the Identification header If it returns Err(sth) when being called with the first packet in a stream, the whole stream is to be considered undecodable as per the Vorbis spec. The function returns Err(`HeaderReadError::HeaderBadType`) if the header type doesn't match the ident header. */ pub fn read_header_ident(packet :&[u8]) -> Result { let mut rdr = BitpackCursor::new(packet); let hd_id = try!(read_header_begin(&mut rdr)); if hd_id != 1 { try!(Err(HeaderReadError::HeaderBadType(hd_id))); } let vorbis_version = try!(rdr.read_u32()); if vorbis_version != 0 { try!(Err(HeaderReadError::UnsupportedVorbisVersion)); } let audio_channels = try!(rdr.read_u8()); let audio_sample_rate = try!(rdr.read_u32()); let bitrate_maximum = try!(rdr.read_i32()); let bitrate_nominal = try!(rdr.read_i32()); let bitrate_minimum = try!(rdr.read_i32()); let blocksize_0 = try!(rdr.read_u4()); let blocksize_1 = try!(rdr.read_u4()); let framing = try!(rdr.read_u8()); if blocksize_0 < 6 || blocksize_0 > 13 || blocksize_1 < 6 || blocksize_1 > 13 || (framing != 1) || blocksize_0 > blocksize_1 || audio_channels == 0 || audio_sample_rate == 0 { try!(Err(HeaderReadError::HeaderBadFormat)); } let hdr :IdentHeader = IdentHeader { audio_channels, audio_sample_rate, bitrate_maximum, bitrate_nominal, bitrate_minimum, blocksize_0, blocksize_1, cached_bs_derived : [ CachedBlocksizeDerived::from_blocksize(blocksize_0), CachedBlocksizeDerived::from_blocksize(blocksize_1), ], }; return Ok(hdr); } #[test] fn test_read_header_ident() { // Valid ident header let test_arr = &[0x01, 0x76, 0x6f, 0x72, 0x62, 0x69, 0x73, 0x00, 0x00, 0x00, 0x00, 0x02, 0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xb5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01]; let hdr = read_header_ident(test_arr).unwrap(); assert_eq!(hdr.audio_channels, 2); assert_eq!(hdr.audio_sample_rate, 0x0000ac44); assert_eq!(hdr.bitrate_maximum, 0); assert_eq!(hdr.bitrate_nominal, 0x0001b580); assert_eq!(hdr.bitrate_minimum, 0); assert_eq!(hdr.blocksize_0, 8); assert_eq!(hdr.blocksize_1, 11); } /** Representation of the comment header The comment header is the second of the three headers inside each vorbis stream. It contains text comment metadata about the stream, encoded as key-value pairs, and the vendor name. */ #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct CommentHeader { /// An identification string of the /// software/library that encoded /// the stream. pub vendor :String, /// A key-value list of the comments /// attached to the stream. pub comment_list :Vec<(String, String)>, } /** Reading the Comment header You should call this function with the second packet in the stream. The function does not check whether the comment field names consist of characters `0x20` through `0x7D` (`0x3D` excluded), as the vorbis spec requires. */ pub fn read_header_comment(packet :&[u8]) -> Result { let mut rdr = Cursor::new(packet); let hd_id = try!(read_header_begin_cursor(&mut rdr)); if hd_id != 3 { try!(Err(HeaderReadError::HeaderBadType(hd_id))); } // First read the vendor string let vendor_length = try!(rdr.read_u32::()) as usize; let mut vendor_buf = vec![0; vendor_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as "unsafe" by rustc. try!(rdr.read_exact(&mut vendor_buf)); let vendor = try!(String::from_utf8(vendor_buf)); // Now read the comments let comment_count = try!(rdr.read_u32::()) as usize; let mut comment_list = Vec::with_capacity(comment_count); for _ in 0 .. comment_count { let comment_length = try!(rdr.read_u32::()) as usize; let mut comment_buf = vec![0; comment_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as "unsafe" by rustc. try!(rdr.read_exact(&mut comment_buf)); let comment = match String::from_utf8(comment_buf) { Ok(comment) => comment, // Uncomment for closer compliance with the spec. // The spec explicitly states that the comment entries // should be UTF-8 formatted, however it seems that other // decoder libraries tolerate non-UTF-8 formatted strings // in comments. This has led to some files circulating // with such errors inside. If we deny to decode such files, // lewton would be the odd one out. Thus we just // gracefully ignore them. Err(_) => continue, }; let eq_idx = match comment.find("=") { Some(k) => k, // Uncomment for closer compliance with the spec. // It appears that some ogg files have fields without a = sign in the comments. // Well there is not much we can do but gracefully ignore their stuff. None => continue // try!(Err(HeaderReadError::HeaderBadFormat)) }; let (key_eq, val) = comment.split_at(eq_idx + 1); let (key, _) = key_eq.split_at(eq_idx); comment_list.push((String::from(key), String::from(val))); } let framing = try!(rdr.read_u8()); if framing != 1 { try!(Err(HeaderReadError::HeaderBadFormat)); } let hdr :CommentHeader = CommentHeader { vendor, comment_list, }; return Ok(hdr); } pub(crate) struct Codebook { pub codebook_dimensions :u16, pub codebook_entries :u32, // None if codebook_lookup_type == 0 pub codebook_vq_lookup_vec :Option>, pub codebook_huffman_tree :VorbisHuffmanTree, } pub(crate) struct Residue { pub residue_type :u8, pub residue_begin :u32, pub residue_end :u32, pub residue_partition_size :u32, pub residue_classifications :u8, pub residue_classbook :u8, pub residue_books :Vec, } pub(crate) struct Mapping { pub mapping_submaps :u8, pub mapping_magnitudes :Vec, pub mapping_angles :Vec, pub mapping_mux :Vec, pub mapping_submap_floors :Vec, pub mapping_submap_residues :Vec, } pub(crate) struct ModeInfo { pub mode_blockflag :bool, pub mode_mapping :u8, } pub(crate) enum Floor { TypeZero(FloorTypeZero), TypeOne(FloorTypeOne), } pub(crate) struct FloorTypeZero { pub floor0_order :u8, pub floor0_rate :u16, pub floor0_bark_map_size :u16, pub floor0_amplitude_bits :u8, pub floor0_amplitude_offset :u8, pub floor0_number_of_books :u8, pub floor0_book_list :Vec, pub cached_bark_cos_omega :[Vec; 2], } pub(crate) struct FloorTypeOne { pub floor1_multiplier :u8, pub floor1_partition_class :Vec, pub floor1_class_dimensions :Vec, pub floor1_class_subclasses :Vec, pub floor1_subclass_books :Vec>, pub floor1_class_masterbooks :Vec, pub floor1_x_list :Vec, pub floor1_x_list_sorted :Vec<(usize, u32)>, } pub(crate) struct ResidueBook { vals_used :u8, val_i :[u8; 8], } impl ResidueBook { pub fn get_val(&self, i :u8) -> Option { if i >= 8 { // This is a precondition... panic!("Tried to get ResidueBook value out of bounds (index = {})", i); } return if self.vals_used & (1 << i) > 0 { Some(self.val_i[i as usize]) } else { None }; } /// Reads the `ResidueBook` from a `BitpackCursor`. fn read_book(rdr :&mut BitpackCursor, vals_used :u8, codebooks :&[Codebook]) -> Result { let mut val_i :[u8; 8] = [0; 8]; for i in 0 .. 7 { if vals_used & (1 << i) == 0 { continue; } let val_entry = try!(rdr.read_u8()); if match codebooks.get(val_entry as usize) { Some(v) => v.codebook_vq_lookup_vec.is_none(), None => true, } { // Both of the cases are forbidden by spec // (the codebook being out of bounds, or // not having a value mapping) try!(Err(HeaderReadError::HeaderBadFormat)) } val_i[i] = val_entry; } return Ok(ResidueBook { vals_used, val_i }); } } pub struct SetupHeader { pub(crate) codebooks :Vec, pub(crate) floors :Vec, pub(crate) residues :Vec, pub(crate) mappings :Vec, pub(crate) modes :Vec, } struct CodebookVqLookup { codebook_lookup_type :u8, codebook_minimum_value :f32, codebook_delta_value :f32, codebook_sequence_p :bool, codebook_multiplicands :Vec, } /// Vector value decode for lookup /// /// Prepares the VQ context vectors for later lookup /// by the codebook abstraction layer. /// /// Returns `codebook_entries` many vectors, /// each being `codebook_dimensions` scalars wide), /// all stored in one Vec. fn lookup_vec_val_decode(lup :&CodebookVqLookup, codebook_entries :u32, codebook_dimensions :u16) -> Vec { let mut value_vectors = Vec::with_capacity( codebook_entries as usize * codebook_dimensions as usize); if lup.codebook_lookup_type == 1 { let codebook_lookup_values = lup.codebook_multiplicands.len(); for lookup_offset in 0 .. codebook_entries { let mut last = 0.; let mut index_divisor = 1; for _ in 0 .. codebook_dimensions { let multiplicand_offset = (lookup_offset / index_divisor as u32) as usize % codebook_lookup_values; let vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 * lup.codebook_delta_value + lup.codebook_minimum_value + last; if lup.codebook_sequence_p { last = vec_elem; } value_vectors.push(vec_elem); index_divisor *= codebook_lookup_values; } } } else { for lookup_offset in 0 .. codebook_entries { let mut last = 0.; let mut multiplicand_offset :usize = lookup_offset as usize * codebook_dimensions as usize; for _ in 0 .. codebook_dimensions { let vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 * lup.codebook_delta_value + lup.codebook_minimum_value + last; if lup.codebook_sequence_p { last = vec_elem; } value_vectors.push(vec_elem); multiplicand_offset += 1; } } } return value_vectors; } /// Small Error type for `BitpackCursor::read_huffman_vq`. /// /// This is in order to enable calling code to distinguish /// between the two cases of the enum. Esp. in some cases /// the decoder might have to reject packages with the /// NoVqLookupForCodebook variant, but have to treat EndOfPacket /// as normal occurence. pub(crate) enum HuffmanVqReadErr { EndOfPacket, NoVqLookupForCodebook, } impl <'a> BitpackCursor <'a> { /// Reads a huffman word using the codebook abstraction via a VQ context pub(crate) fn read_huffman_vq<'b>(&mut self, b :&'b Codebook) -> Result<&'b[f32], HuffmanVqReadErr> { let idx = match self.read_huffman(&b.codebook_huffman_tree) { Ok(v) => v as usize, Err(_) => return Err(HuffmanVqReadErr::EndOfPacket), }; let codebook_vq_lookup_vec :&[f32] = match b.codebook_vq_lookup_vec.as_ref() { Some(ref v) => v, None => return Err(HuffmanVqReadErr::NoVqLookupForCodebook), }; let dim = b.codebook_dimensions as usize; return Ok(&codebook_vq_lookup_vec[idx * dim .. (idx + 1) * dim]); } } static MAX_BASES_WITHOUT_OVERFLOW : &[u32] = &[ 0xffffffff, 0xffffffff, 0x0000ffff, 0x00000659, 0x000000ff, 0x00000054, 0x00000028, 0x00000017, 0x0000000f, 0x0000000b, 0x00000009, 0x00000007, 0x00000006, 0x00000005, 0x00000004, 0x00000004, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002, 0x00000002]; static MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW : &[u8] = &[ 0x1f, 0x1f, 0x0f, 0x0a, 0x07, 0x06, 0x05, 0x04, 0x03, 0x03, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01]; // For this little function I won't include the num crate. // precondition: base ^ exponent must not overflow. fn exp_fast(base :u32, exponent: u8) -> u32 { let mut res :u32 = 1; let mut selfmul = base; for i in 0 .. 8 { if (1 << i) & exponent > 0 { res *= selfmul; } if let Some(newselfmul) = u32::checked_mul(selfmul, selfmul) { selfmul = newselfmul; } else { // Okay, now we have to find out // whether this matters or not. // Check whether selfmul would have been needed. if i < 7 && (exponent >> (i + 1)) > 0 { panic!("Overflow when squaring for exp_fast, \ precondition violated!"); } return res; } } return res; } /// Returns, as defined in the vorbis spec: /// "the greatest integer for which to `[return_value]` the power of `[codebook_dimensions]` is less than or equal to `[codebook_entries]`" /// Essentially an "nth-root" algorithm. /// About the speed: /// Probably its super-optimized as it uses no floats, /// probably smarter algorithms using floats would be faster here. No idea. /// Either way, stackoverflow gave the (great) motivation for the algorithm: /// http://stackoverflow.com/questions/7407752 fn lookup1_values(codebook_entries :u32, codebook_dimensions :u16) -> u32 { if codebook_dimensions >= 32 { // For codebook_dimensions >= 32 we'd already overflow the u32 range if // we computed 2 ^ codebook_dimensions. // Therefore, the result must be less than 2. return if codebook_entries == 0 { 0 } else { 1 }; } // Now do a binary search. // We use two static helper arrays here. Both take the // exponent (codebook_dimensions here) as index. // The first array, MAX_BASES_WITHOUT_OVERFLOW contains // the base that doesn't generate an overflow for the // given exponent. // The second array MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW // contains the number of the highest set bit in // the corresponding entry in MAX_BASES_WITHOUT_OVERFLOW. // This is the first bit that is "disputed" in the binary // search to follow: we check the bases to support the // claim by manual exponentiation. let max_base_bits = MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW[ codebook_dimensions as usize]; let max_base = MAX_BASES_WITHOUT_OVERFLOW[codebook_dimensions as usize]; let mut base_bits :u32 = 0; for i in 0 .. max_base_bits + 1 { let cur_disputed_bit :u32 = 1 << (max_base_bits - i); base_bits |= cur_disputed_bit; if max_base < base_bits || exp_fast(base_bits, codebook_dimensions as u8) > codebook_entries { base_bits &= !cur_disputed_bit; } } return base_bits; } #[test] fn test_lookup1_values() { // First, with base two: // 2 ^ 10 = 1024 assert_eq!(lookup1_values(1025, 10), 2); assert_eq!(lookup1_values(1024, 10), 2); assert_eq!(lookup1_values(1023, 10), 1); // Now, the searched base is five: // 5 ^ 5 = 3125 assert_eq!(lookup1_values(3126, 5), 5); assert_eq!(lookup1_values(3125, 5), 5); assert_eq!(lookup1_values(3124, 5), 4); // Now some exotic tests (edge cases :p): assert_eq!(lookup1_values(1, 1), 1); assert_eq!(lookup1_values(0, 15), 0); assert_eq!(lookup1_values(0, 0), 0); assert_eq!(lookup1_values(1, 0), std::u32::MAX); assert_eq!(lookup1_values(400, 0), std::u32::MAX); } /// Reads a codebook which is part of the setup header packet. fn read_codebook(rdr :&mut BitpackCursor) -> Result { // 1. Read the sync pattern let sync_pattern = try!(rdr.read_u24()); if sync_pattern != 0x564342 { try!(Err(HeaderReadError::HeaderBadFormat)); } // 2. Read the _dimension, _entries fields and the ordered bitflag let codebook_dimensions = try!(rdr.read_u16()); let codebook_entries = try!(rdr.read_u24()); let ordered = try!(rdr.read_bit_flag()); // 3. Read the codeword lengths let mut codebook_codeword_lengths = Vec::with_capacity( convert_to_usize!(codebook_entries, u32)); if !ordered { let sparse = try!(rdr.read_bit_flag()); for _ in 0 .. codebook_entries { let length = if sparse { let flag = try!(rdr.read_bit_flag()); if flag { try!(rdr.read_u5()) + 1 } else { /* The spec here asks that we should mark that the entry is unused. But 0 already fulfills this purpose, as everywhere else its guaranteed that the length is > 0. No messing with Option needed here :) */ 0 } } else { try!(rdr.read_u5()) + 1 }; codebook_codeword_lengths.push(length); } } else { let mut current_entry :u32 = 0; let mut current_length = try!(rdr.read_u5()) + 1; while current_entry < codebook_entries { let number = try!(rdr.read_dyn_u32( ::ilog((codebook_entries - current_entry) as u64))); for _ in current_entry .. current_entry + number { codebook_codeword_lengths.push(current_length); } current_entry += number; current_length += 1; if current_entry as u32 > codebook_entries { try!(Err(HeaderReadError::HeaderBadFormat)); } } } // 4. Read the vector lookup table let codebook_lookup_type = try!(rdr.read_u4()); if codebook_lookup_type > 2 { // Not decodable per vorbis spec try!(Err(HeaderReadError::HeaderBadFormat)); } let codebook_lookup :Option = if codebook_lookup_type == 0 { None } else { let codebook_minimum_value = try!(rdr.read_f32()); let codebook_delta_value = try!(rdr.read_f32()); let codebook_value_bits = try!(rdr.read_u4()) + 1; let codebook_sequence_p = try!(rdr.read_bit_flag()); let codebook_lookup_values :u64 = if codebook_lookup_type == 1 { lookup1_values(codebook_entries, codebook_dimensions) as u64 } else { codebook_entries as u64 * codebook_dimensions as u64 }; let mut codebook_multiplicands = Vec::with_capacity( convert_to_usize!(codebook_lookup_values, u64)); for _ in 0 .. codebook_lookup_values { codebook_multiplicands.push(try!(rdr.read_dyn_u32(codebook_value_bits))); } Some(CodebookVqLookup { codebook_lookup_type, codebook_minimum_value, codebook_delta_value, codebook_sequence_p, codebook_multiplicands, }) }; let codebook_vq_lookup_vec = codebook_lookup.as_ref().map(|lup| { lookup_vec_val_decode(lup, codebook_entries, codebook_dimensions) }); return Ok(Codebook { codebook_dimensions, codebook_entries, codebook_vq_lookup_vec, codebook_huffman_tree : try!(VorbisHuffmanTree::load_from_array(&codebook_codeword_lengths)), }); } /// Reads a Floor which is part of the setup header packet. /// The `codebook_cnt` param is required to check for compliant streams fn read_floor(rdr :&mut BitpackCursor, codebook_cnt :u16, blocksizes :(u8, u8)) -> Result { let floor_type = try!(rdr.read_u16()); match floor_type { 0 => { let floor0_order = try!(rdr.read_u8()); let floor0_rate = try!(rdr.read_u16()); let floor0_bark_map_size = try!(rdr.read_u16()); let floor0_amplitude_bits = try!(rdr.read_u6()); if floor0_amplitude_bits > 64 { // Unfortunately the audio decoder part // doesn't support values > 64 because rust has no // 128 bit integers yet. // TODO when support is added, remove this // check. try!(Err(HeaderReadError::HeaderBadFormat)); } let floor0_amplitude_offset = try!(rdr.read_u8()); let floor0_number_of_books = try!(rdr.read_u4()) + 1; let mut floor0_book_list = Vec::with_capacity( convert_to_usize!(floor0_number_of_books, u8)); for _ in 0 .. floor0_number_of_books { let value = try!(rdr.read_u8()); if value as u16 > codebook_cnt { try!(Err(HeaderReadError::HeaderBadFormat)); } floor0_book_list.push(value); } Ok(Floor::TypeZero(FloorTypeZero { floor0_order, floor0_rate, floor0_bark_map_size, floor0_amplitude_bits, floor0_amplitude_offset, floor0_number_of_books, floor0_book_list, cached_bark_cos_omega : [ compute_bark_map_cos_omega(1 << (blocksizes.0 - 1), floor0_rate, floor0_bark_map_size), compute_bark_map_cos_omega(1 << (blocksizes.1 - 1), floor0_rate, floor0_bark_map_size), ] })) }, 1 => { let floor1_partitions = try!(rdr.read_u5()); let mut maximum_class :i8 = -1; let mut floor1_partition_class_list = Vec::with_capacity( floor1_partitions as usize); for _ in 0 .. floor1_partitions { let cur_class = try!(rdr.read_u4()); maximum_class = if cur_class as i8 > maximum_class { cur_class as i8 } else { maximum_class }; floor1_partition_class_list.push(cur_class); } // TODO one day try out whether its more performant // to have these two arrays in one, its wasteful to allocate // 16 bit so that one can store 5 bits. let mut floor1_class_dimensions = Vec::with_capacity((maximum_class + 1) as usize); let mut floor1_class_subclasses = Vec::with_capacity((maximum_class + 1) as usize); let mut floor1_subclass_books = Vec::with_capacity((maximum_class + 1) as usize); let mut floor1_class_masterbooks = Vec::with_capacity((maximum_class + 1) as usize); for _ in 0 .. maximum_class + 1 { floor1_class_dimensions.push(try!(rdr.read_u3()) + 1); let cur_subclass = try!(rdr.read_u2()); floor1_class_subclasses.push(cur_subclass); if cur_subclass != 0 { let cur_masterbook = try!(rdr.read_u8()); if cur_masterbook as u16 >= codebook_cnt { // undecodable as per spec try!(Err(HeaderReadError::HeaderBadFormat)); } floor1_class_masterbooks.push(cur_masterbook); } else { // Some value... This never gets read, // but Rust requires everything to be initialized, // we can't increase the counter without initialisation. floor1_class_masterbooks.push(0); } let cur_books_cnt :u8 = 1 << cur_subclass; let mut cur_books = Vec::with_capacity(cur_books_cnt as usize); for _ in 0 .. cur_books_cnt { // The fact that we need i16 here (and shouldn't do // wrapping sub) is only revealed if you read the // "packet decode" part of the floor 1 spec... let cur_book = (try!(rdr.read_u8()) as i16) - 1; if cur_book >= codebook_cnt as i16 { // undecodable as per spec try!(Err(HeaderReadError::HeaderBadFormat)); } cur_books.push(cur_book); } floor1_subclass_books.push(cur_books); } let floor1_multiplier = try!(rdr.read_u2()) + 1; let rangebits = try!(rdr.read_u4()); let mut floor1_values :u16 = 2; // Calculate the count before doing anything else for cur_class_num in &floor1_partition_class_list { floor1_values += floor1_class_dimensions[*cur_class_num as usize] as u16; } if floor1_values > 65 { // undecodable as per spec try!(Err(HeaderReadError::HeaderBadFormat)); } let mut floor1_x_list = Vec::with_capacity(floor1_values as usize); floor1_x_list.push(0); floor1_x_list.push(1u32 << rangebits); for cur_class_num in &floor1_partition_class_list { for _ in 0 .. floor1_class_dimensions[*cur_class_num as usize] { floor1_x_list.push(try!(rdr.read_dyn_u32(rangebits))); } } // Now do an uniqueness check on floor1_x_list // to check decodability. let mut floor1_x_list_sorted = floor1_x_list.iter().cloned() .enumerate().collect::>(); floor1_x_list_sorted.sort_by(|a, b| a.1.cmp(&b.1)); // 0 is guaranteed to be in the list, // and due to sorting it will be first. let mut last = 1; for el in &floor1_x_list_sorted { if el.1 == last { // duplicate entry found // undecodable as per spec try!(Err(HeaderReadError::HeaderBadFormat)); } last = el.1; } // Only now return the result Ok(Floor::TypeOne(FloorTypeOne { floor1_multiplier, floor1_partition_class : floor1_partition_class_list, floor1_class_dimensions, floor1_class_subclasses, floor1_subclass_books, floor1_class_masterbooks, floor1_x_list, floor1_x_list_sorted, })) }, // Type greater than 1 is error condition per spec _ => Err(HeaderReadError::HeaderBadFormat), } } /// Reads a Residue which is part of the setup header packet. /// The `codebook_cnt` param is required to check for compliant streams fn read_residue(rdr :&mut BitpackCursor, codebooks :&[Codebook]) -> Result { let residue_type = try!(rdr.read_u16()); if residue_type > 2 { // Undecodable by spec try!(Err(HeaderReadError::HeaderBadFormat)); } let residue_begin = try!(rdr.read_u24()); let residue_end = try!(rdr.read_u24()); if residue_begin > residue_end { // If residue_begin < residue_end, we'll get // errors in audio parsing code. // As the idea of residue end being before begin // sounds quite wrong anyway, we already error // earlier, in header parsing code. try!(Err(HeaderReadError::HeaderBadFormat)); } let residue_partition_size = try!(rdr.read_u24()) + 1; let residue_classifications = try!(rdr.read_u6()) + 1; let residue_classbook = try!(rdr.read_u8()); // Read the bitmap pattern: let mut residue_cascade = Vec::with_capacity(residue_classifications as usize); for _ in 0 .. residue_classifications { let mut high_bits = 0; let low_bits = try!(rdr.read_u3()); let bitflag = try!(rdr.read_bit_flag()); if bitflag { high_bits = try!(rdr.read_u5()); } residue_cascade.push((high_bits << 3) | low_bits); } let mut residue_books = Vec::with_capacity(residue_classifications as usize); // Read the list of book numbers: for cascade_entry in &residue_cascade { residue_books.push(try!( ResidueBook::read_book(rdr, *cascade_entry, codebooks))); } if residue_classbook as usize >= codebooks.len() { // Undecodable because residue_classbook must be valid index try!(Err(HeaderReadError::HeaderBadFormat)); } /* // Currently we check below condition in audio decode, following the spec, // section 3.3., saying that it only renders the packet that wants to use the // invalid codebook invalid, but not the whole stream only because there is a // residue in the header (which may never be used). if codebooks[residue_classbook as usize].codebook_vq_lookup_vec.is_none() { // Undecodable because residue_classbook must be valid index try!(Err(HeaderReadError::HeaderBadFormat)); }*/ return Ok(Residue { residue_type : residue_type as u8, residue_begin, residue_end, residue_partition_size, residue_classifications, residue_classbook, residue_books, }); } /// Reads a "Mapping" which is part of the setup header packet. fn read_mapping(rdr :&mut BitpackCursor, audio_chan_ilog :u8, audio_channels :u8, floor_count :u8, residue_count :u8) -> Result { let mapping_type = try!(rdr.read_u16()); if mapping_type > 0 { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } let mapping_submaps = match try!(rdr.read_bit_flag()) { true => try!(rdr.read_u4()) + 1, false => 1, }; let mapping_coupling_steps = match try!(rdr.read_bit_flag()) { true => try!(rdr.read_u8()) as u16 + 1, false => 0, }; let mut mapping_magnitudes = Vec::with_capacity(mapping_coupling_steps as usize); let mut mapping_angles = Vec::with_capacity(mapping_coupling_steps as usize); for _ in 0 .. mapping_coupling_steps { let cur_mag = try!(rdr.read_dyn_u8(audio_chan_ilog)); let cur_angle = try!(rdr.read_dyn_u8(audio_chan_ilog)); if (cur_angle == cur_mag) || (cur_mag >= audio_channels) || (cur_angle >= audio_channels) { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } mapping_magnitudes.push(cur_mag); mapping_angles.push(cur_angle); } let reserved = try!(rdr.read_u2()); if reserved != 0 { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } let mapping_mux = if mapping_submaps > 1 { let mut m = Vec::with_capacity(audio_channels as usize); for _ in 0 .. audio_channels { let val = try!(rdr.read_u4()); if val >= mapping_submaps { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } m.push(val); }; m } else { vec![0; audio_channels as usize] }; let mut mapping_submap_floors = Vec::with_capacity(mapping_submaps as usize); let mut mapping_submap_residues = Vec::with_capacity(mapping_submaps as usize); for _ in 0 .. mapping_submaps { // To whom those reserved bits may concern. // I have discarded them! try!(rdr.read_u8()); let cur_floor = try!(rdr.read_u8()); let cur_residue = try!(rdr.read_u8()); if cur_floor >= floor_count || cur_residue >= residue_count { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } mapping_submap_floors.push(cur_floor); mapping_submap_residues.push(cur_residue); } return Ok(Mapping { mapping_submaps, mapping_magnitudes, mapping_angles, mapping_mux, mapping_submap_floors, mapping_submap_residues, }); } /// Reads a ModeInfo which is part of the setup header packet. fn read_mode_info(rdr :&mut BitpackCursor, mapping_count :u8) -> Result { let mode_blockflag = try!(rdr.read_bit_flag()); let mode_windowtype = try!(rdr.read_u16()); let mode_transformtype = try!(rdr.read_u16()); let mode_mapping = try!(rdr.read_u8()); // Verifying ranges if mode_windowtype != 0 || mode_transformtype != 0 || mode_mapping >= mapping_count { // Undecodable per spec try!(Err(HeaderReadError::HeaderBadFormat)); } return Ok(ModeInfo { mode_blockflag, mode_mapping, }); } /// Reading the setup header. /// /// The audio channel and blocksize info needed by the function /// can be obtained from the ident header. pub fn read_header_setup(packet :&[u8], audio_channels :u8, blocksizes :(u8, u8)) -> Result { let mut rdr = BitpackCursor::new(packet); let hd_id = try!(read_header_begin(&mut rdr)); if hd_id != 5 { try!(Err(HeaderReadError::HeaderBadType(hd_id))); } // Little preparation -- needed later let audio_chan_ilog = ::ilog((audio_channels - 1) as u64); //::print_u8_slice(packet); // 1. Read the codebooks let vorbis_codebook_count :u16 = try!(rdr.read_u8()) as u16 + 1; let mut codebooks = Vec::with_capacity(vorbis_codebook_count as usize); for _ in 0 .. vorbis_codebook_count { codebooks.push(try!(read_codebook(&mut rdr))); } // 2. Read the time domain transforms let vorbis_time_count :u8 = try!(rdr.read_u6()) + 1; for _ in 0 .. vorbis_time_count { if try!(rdr.read_u16()) != 0 { try!(Err(HeaderReadError::HeaderBadFormat)); } } // 3. Read the floor values let vorbis_floor_count :u8 = try!(rdr.read_u6()) + 1; let mut floors = Vec::with_capacity(vorbis_floor_count as usize); for _ in 0 .. vorbis_floor_count { floors.push(try!(read_floor(&mut rdr, vorbis_codebook_count, blocksizes))); } // 4. Read the residue values let vorbis_residue_count :u8 = try!(rdr.read_u6()) + 1; let mut residues = Vec::with_capacity(vorbis_residue_count as usize); for _ in 0 .. vorbis_residue_count { residues.push(try!(read_residue(&mut rdr, &codebooks))); } // 5. Read the mappings let vorbis_mapping_count :u8 = try!(rdr.read_u6()) + 1; let mut mappings = Vec::with_capacity(vorbis_mapping_count as usize); for _ in 0 .. vorbis_mapping_count { mappings.push(try!(read_mapping(& mut rdr, audio_chan_ilog, audio_channels, vorbis_floor_count, vorbis_residue_count))); } // 6. Read the modes let vorbis_mode_count :u8 = try!(rdr.read_u6()) + 1; let mut modes = Vec::with_capacity(vorbis_mode_count as usize); for _ in 0 .. vorbis_mode_count { modes.push(try!(read_mode_info(& mut rdr, vorbis_mapping_count))); } // Now we only have to make sure the framing bit is set, // and we can successfully return the setup header! let framing :bool = try!(rdr.read_bit_flag()); if !framing { try!(Err(HeaderReadError::HeaderBadFormat)); } return Ok(SetupHeader { codebooks, floors, residues, mappings, modes, }); } lewton-0.10.2/src/header_cached.rs010066400017500001750000000104551376463412200151560ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Cached header info This mod contains logic to generate and deal with data derived from header information that's used later in the decode process. The caching is done to speed up decoding. */ pub struct TwiddleFactors { pub a :Vec, pub b :Vec, pub c :Vec, } pub struct CachedBlocksizeDerived { pub twiddle_factors : TwiddleFactors, pub window_slope : Vec, pub bitrev : Vec, } impl CachedBlocksizeDerived { pub fn from_blocksize(bs :u8) -> Self { CachedBlocksizeDerived { window_slope : generate_window((1 << (bs as u16)) >> 1), twiddle_factors : compute_twiddle_factors(bs), bitrev : compute_bitreverse(bs), } } } fn win_slope(x :u16, n :u16) -> f32 { // please note that there might be a MISTAKE // in how the spec specifies the right window slope // function. See "4.3.1. packet type, mode and window decode" // step 7 where it adds an "extra" pi/2. // The left slope doesn't have it, only the right one. // as stb_vorbis shares the window slope generation function, // The *other* possible reason is that we don't need the right // window for anything. TODO investigate this more. let v = (0.5 * std::f32::consts::PI * (x as f32 + 0.5) / n as f32).sin(); return (0.5 * std::f32::consts::PI * v * v ).sin(); } fn generate_window(n :u16) -> Vec { let mut window = Vec::with_capacity(n as usize); for i in 0 .. n { window.push(win_slope(i, n)); } return window; } fn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors { let n = 1 << (blocksize as u16); let n2 = n >> 1; let n4 = n >> 2; let n8 = n >> 3; let mut a = Vec::with_capacity(n2); let mut b = Vec::with_capacity(n2); let mut c = Vec::with_capacity(n4); let mut k2 = 0; let pi_4_n = 4.0 * std::f32::consts::PI / (n as f32); let pi_05_n = 0.5 * std::f32::consts::PI / (n as f32); let pi_2_n = 2.0 * std::f32::consts::PI / (n as f32); for k in 0..n4 { a.push( f32::cos((k as f32) * pi_4_n)); a.push(-f32::sin((k as f32) * pi_4_n)); b.push( f32::cos(((k2+1) as f32) * pi_05_n) * 0.5); b.push( f32::sin(((k2+1) as f32) * pi_05_n) * 0.5); k2 += 2; } k2 = 0; for _ in 0..n8 { c.push( f32::cos(((k2 + 1) as f32) * pi_2_n)); c.push(-f32::sin(((k2 + 1) as f32) * pi_2_n)); k2 += 2; } return TwiddleFactors { a, b, c, }; } fn compute_bitreverse(blocksize :u8) -> Vec { let ld = blocksize as u16; let n = 1 << blocksize; let n8 = n >> 3; let mut rev = Vec::with_capacity(n8); for i in 0 .. n8 { rev.push((::bit_reverse(i as u32) as u32 >> (32 - ld + 3)) << 2); } return rev; } #[test] fn test_compute_bitreverse() { let br = compute_bitreverse(8); // The output was generated from the output of the // original stb_vorbis function. let cmp_arr = &[ 0, 64, 32, 96, 16, 80, 48, 112, 8, 72, 40, 104, 24, 88, 56, 120, 4, 68, 36, 100, 20, 84, 52, 116, 12, 76, 44, 108, 28, 92, 60, 124]; assert_eq!(br, cmp_arr); } #[inline] fn bark(x :f32) -> f32 { 13.1 * (0.00074 * x).atan() + 2.24 * (0.0000000185*x*x).atan() + 0.0001 * x } /// Precomputes bark map values used by floor type 0 packets /// /// Precomputes the cos(omega) values for use by floor type 0 computation. /// /// Note that there is one small difference to the spec: the output /// vec is n elements long, not n+1. The last element (at index n) /// is -1 in the spec, we lack it. Users of the result of this function /// implementation should use it "virtually". pub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16, floor0_bark_map_size :u16) -> Vec { let mut res = Vec::with_capacity(n as usize); let hfl = floor0_rate as f32 / 2.0; let hfl_dn = hfl / n as f32; let foobar_const_part = floor0_bark_map_size as f32 / bark(hfl); // Bark map size minus 1: let bms_m1 = floor0_bark_map_size as f32 - 1.0; let omega_factor = std::f32::consts::PI / floor0_bark_map_size as f32; for i in 0 .. n { let foobar = (bark(i as f32 * hfl_dn) * foobar_const_part).floor(); let map_elem = foobar.min(bms_m1); let cos_omega = (map_elem * omega_factor).cos(); res.push(cos_omega); } return res; } lewton-0.10.2/src/huffman_tree.rs010066400017500001750000000366451376463323000151120ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Huffman tree unpacking and traversal This mod contains the `VorbisHuffmanTree` struct which can be loaded from the `codebook_codeword_lengths` array specified for each codebook in the vorbis setup header. Once decoding is happening, you are more interested in the `VorbisHuffmanIter` struct which provides you with facilities to load a value bit by bit. */ struct HuffTree { // True iff every sub-tree in this tree // either has two direct children or none even_childs :bool, payload :Option, l :Option>, r :Option>, } /* use std::fmt; impl fmt::Debug for HuffTree { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt_rec(s :&HuffTree, f: &mut fmt::Formatter, depth :u32) -> fmt::Result { macro_rules! depth_print { ($f:ident, $depth:ident) => { for _ in 0..$depth { try!(write!($f, "| ")); } }} if s.l.is_some() || s.r.is_some() { try!(writeln!(f, "ec: {:?}, pl: {:?}, LIS {:?} RIS {:?}", s.even_childs, s.payload, s.l.is_some(), s.r.is_some())); } else { try!(writeln!(f, "ec: {:?}, pl: {:?}", s.even_childs, s.payload)); } if let Some(ref v) = s.l { depth_print!(f, depth); try!(write!(f, "LEFT ")); try!(fmt_rec(&*v, f, depth + 1)); } if let Some(ref v) = s.r { depth_print!(f, depth); try!(write!(f, "RIGT ")); try!(fmt_rec(&*v, f, depth + 1)); } return Ok(()); } try!(fmt_rec(self, f, 1)); return Ok(()); } } // */ impl HuffTree { /// Returns whether the addition was successful pub fn insert_rec(&mut self, payload :u32, depth :u8) -> bool { //print!("INSERT payload {:?} depth {:?} ", payload, depth); if self.payload.is_some() { //println!(" => OCCUPIED AS LEAF"); return false; } if depth == 0 { if !(self.l.is_none() && self.r.is_none()) { //println!(" => INNER NODE"); return false; } self.payload = Some(payload); //println!(" => ADDED"); return true; } if self.even_childs { //println!(" => HAS EVEN CHILDS"); match &mut self.l { &mut Some(_) => return false, &mut None => { let mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None }; new_node.insert_rec(payload, depth - 1); self.l = Some(Box::new(new_node)); self.even_childs = false; return true; } } } else { //println!(" => HAS NOT EVEN CHILDS"); // First try left branch let left = self.l.as_mut().unwrap(); if !left.even_childs { if left.insert_rec(payload, depth - 1) { self.even_childs = left.even_childs && if let &mut Some(ref mut right) = &mut self.r.as_mut() { right.even_childs } else { false }; return true; } } // Left sub tree was either full or leaf // Therefore, put it in the right branch now // As left has even_childs == true, right causes // us to have even_childs == false. return match self.r { Some(ref mut right) => { let success = right.insert_rec(payload, depth - 1); self.even_childs = left.even_childs && right.even_childs; success }, None => { let mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None }; let success = new_node.insert_rec(payload, depth - 1); self.even_childs = left.even_childs && new_node.even_childs; self.r = Some(Box::new(new_node)); success } }; } } } #[derive(Debug)] pub enum HuffmanError { Overspecified, Underpopulated, InvalidSingleEntry, } #[derive(Clone, Copy)] enum UnrolledLookupEntry { /// The specified entry was found in the lookup array /// /// First param: offset by which to advance the reader /// Second param: the payload HasEntry(u8, u32), /// Seems the given input is inconclusive and not complete yet. /// /// The argument contains a hint that is an offset inside desc_prog /// to help to advance the reader. InconclusiveWithHint(u32), /// Seems the given input is inconclusive and not complete yet. Inconclusive, } pub enum PeekedDataLookupResult<'l> { /// The supplied info is not enough to result in a payload directly. /// /// First param is the number of bits to advance. /// /// The returned iterator has state up to the count of bits that could be used. Iter(u8, VorbisHuffmanIter<'l>), /// The supplied info is enough to map to a payload /// /// First param is the number of bits to advance. Second is payload. PayloadFound(u8, u32), } /// Huffman tree representation pub struct VorbisHuffmanTree { // Format: three bytes per non leaf node, one byte per leaf node. // First byte is the payload container, // second and third point to the indices inside the vector that // have left and right children. // If the node is a leaf the highest bit of the payload container 0, // if it has children the bit is 1. If its a leaf the lower 31 bits of the // payload container form the actual payload. desc_prog :Vec, unrolled_entries :[UnrolledLookupEntry; 256], } impl VorbisHuffmanTree { /// Constructs a new `VorbisHuffmanTree` instance from the passed array, /// like the vorbis spec demands. /// /// Returns the resulting tree if the array results in a valid (neither /// underspecified nor overspecified) tree. pub fn load_from_array(codebook_codeword_lengths :&[u8]) -> Result { // First step: generate a simple tree representing the // Huffman tree let mut simple_tree = HuffTree { even_childs :true, payload :None, l :None, r :None }; let mut cnt :usize = 0; let mut last_valid_idx = None; for (i, &codeword_length) in codebook_codeword_lengths.iter().enumerate() { if codeword_length == 0 { continue; } cnt += 1; last_valid_idx = Some(i); if !simple_tree.insert_rec(i as u32, codeword_length) { try!(Err(HuffmanError::Overspecified)) /* Overspecified, can't be put into tree */ } } //println!("The tree:\n{:?}", simple_tree); // Single entry codebook special handling if cnt == 1 { let decoded = last_valid_idx.unwrap(); let encoded_len = codebook_codeword_lengths[decoded]; if encoded_len == 1 { // Return a vorbis tree that returns decoded for any single bit input return Ok(VorbisHuffmanTree { desc_prog :vec![1u32 << 31, 3, 3, decoded as u32], unrolled_entries :[ UnrolledLookupEntry::HasEntry(1, decoded as u32); 256 ], }); } else { // Single entry codebooks must have 1 as their only length entry try!(Err(HuffmanError::InvalidSingleEntry)) } } if !simple_tree.even_childs { try!(Err(HuffmanError::Underpopulated)); /* Underpopulated */ } // Second step: generate the actual desc_prog // by pre_order traversal of the tree. // // The general advantage of this approach over one with only the simple tree // is better cache locality and less memory requirements (at least after the // setup with the simple tree). let mut desc_prog = Vec::with_capacity(cnt); fn traverse(tree :& HuffTree, desc_prog :&mut Vec) -> u32 { let cur_pos = desc_prog.len() as u32; let has_children = tree.l.is_some() || tree.r.is_some(); let entry = ((has_children as u32) << 31) | tree.payload.unwrap_or(0); //println!("push node (w_children : {:?}) at {:?} : {:?}", has_children, cur_pos, entry); desc_prog.push(entry); if has_children { desc_prog.push(0); desc_prog.push(0); desc_prog[cur_pos as usize + 1] = traverse(tree.l.as_ref().unwrap(), desc_prog); /*println!("left child of node {:?}: at {:?}", cur_pos, desc_prog[cur_pos as usize + 1]);// */ desc_prog[cur_pos as usize + 2] = traverse(tree.r.as_ref().unwrap(), desc_prog); /*println!("right child of node {:?}: at {:?}", cur_pos, desc_prog[cur_pos as usize + 2]);// */ } return cur_pos; } assert_eq!(traverse(&simple_tree, &mut desc_prog), 0); // Third step: generate unrolled entries array // Also by pre_order traversal. // // This gives us a speedup over desc_prog as reading the unrolled // entries should involve less branching and less lookups overall. let mut unrolled_entries = [UnrolledLookupEntry::Inconclusive; 256]; fn uroll_traverse(tree :& HuffTree, unrolled_entries :&mut [UnrolledLookupEntry; 256], prefix :u32, prefix_idx :u8, desc_prog :&[u32], desc_prog_idx :u32) { let has_children = tree.l.is_some() || tree.r.is_some(); if has_children { // There are children. // We'd like to recurse deeper. Can we? if prefix_idx == 8 { // No we can't. // The tree is too deep. unrolled_entries[prefix as usize] = UnrolledLookupEntry::InconclusiveWithHint(desc_prog_idx); } else { // Recurse deeper. uroll_traverse(tree.l.as_ref().unwrap(), unrolled_entries, prefix + (0 << prefix_idx), prefix_idx + 1, desc_prog, desc_prog[desc_prog_idx as usize + 1]); uroll_traverse(tree.r.as_ref().unwrap(), unrolled_entries, prefix + (1 << prefix_idx), prefix_idx + 1, desc_prog, desc_prog[desc_prog_idx as usize + 2]); } } else { // No children, fill the entries in the range according to // the prefix we have. let payload = tree.payload.unwrap(); let it = 1 << prefix_idx; let mut i = prefix as usize; for _ in 1 .. (1u16 << (8 - prefix_idx)) { unrolled_entries[i] = UnrolledLookupEntry::HasEntry(prefix_idx, payload); i += it; } } } if cnt > 0 { uroll_traverse(&simple_tree, &mut unrolled_entries, 0, 0, &desc_prog, 0); } // Now we are done, return the result return Ok(VorbisHuffmanTree { desc_prog, unrolled_entries, }); } /// Returns an iterator over this tree. pub fn iter<'l>(&'l self) -> VorbisHuffmanIter<'l> { return VorbisHuffmanIter { desc_prog :&self.desc_prog, pos :0 }; } /// Resolves a given number of peeked bits. /// /// Returns whether the data given is enough to uniquely identify a /// tree element, or whether only an iterator that's progressed by /// a given amount can be returned. Also, info is returned about how /// far the reader can be advanced. pub fn lookup_peeked_data<'l>(&'l self, bit_count :u8, peeked_data :u32) -> PeekedDataLookupResult<'l> { if bit_count > 8 { panic!("Bit count {} larger than allowed 8", bit_count); } use self::UnrolledLookupEntry::*; use self::PeekedDataLookupResult::*; return match self.unrolled_entries[peeked_data as usize] { // If cnt_to_remove is bigger than bit_count the result is inconclusive. // Return in this case. HasEntry(cnt_to_remove, payload) if cnt_to_remove <= bit_count => PayloadFound(cnt_to_remove, payload), InconclusiveWithHint(hint) => Iter(8, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : hint }), _ => Iter(0, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : 0 }), }; } } /// Iterator on the Huffman tree pub struct VorbisHuffmanIter<'a> { desc_prog :&'a Vec, pos :u32, } impl<'a> VorbisHuffmanIter<'a> { /// Iterate one level deeper inside the tree. /// Returns `Some(p)` if it encounters a leaf with a payload p, /// None if it only processed an inner node. /// /// Inner nodes don't carry payloads in huffman trees. /// /// If this function encounters a leaf, it automatically resets /// the iterator to its starting state. /// /// # Panics /// /// Panics if the vorbis huffman treee is empty. It has to be found out /// what to do if the huffman tree is empty, whether to reject the stream, /// or whether to do sth else. Finding this out is a TODO. pub fn next(&mut self, bit :bool) -> Option { // Assertion test for the paranoid and testing, comment out if you are: /*let cur_entry = self.desc_prog[self.pos as usize]; assert!((cur_entry & (1u32 << 31)) != 0);*/ //print!("With bit {:?}, pos {:?} becomes pos ", bit, self.pos); self.pos = self.desc_prog[self.pos as usize + 1 + bit as usize]; //print!("{:?}", self.pos); let child = self.desc_prog[self.pos as usize]; if (child & (1u32 << 31)) != 0 { //println!(" => None"); // child has children return None; } else { //println!(" => Some({:?})", child); // child has no children, it's a leaf self.pos = 0; return Some(child); } } } #[cfg(test)] impl VorbisHuffmanTree { fn iter_test(&self, path :u32, path_len :u8, expected_val :u32) { let mut itr = self.iter(); for i in 1 .. path_len { assert_eq!(itr.next((path & (1 << (path_len - i))) != 0), None); } assert_eq!(itr.next((path & 1) != 0), Some(expected_val)); } } #[test] fn test_huffman_tree() { // Official example from the vorbis spec section 3.2.1 let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3]).unwrap(); tree.iter_test(0b00, 2, 0); tree.iter_test(0b0100, 4, 1); tree.iter_test(0b0101, 4, 2); tree.iter_test(0b0110, 4, 3); tree.iter_test(0b0111, 4, 4); tree.iter_test(0b10, 2, 5); tree.iter_test(0b110, 3, 6); tree.iter_test(0b111, 3, 7); // Some other example // we mostly test the length (max 32) here VorbisHuffmanTree::load_from_array(&[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32]).unwrap(); } #[test] fn test_issue_8() { // regression test for issue 8 // make sure that it doesn't panic. let _ = VorbisHuffmanTree::load_from_array(&[0; 625]); } #[test] fn test_under_over_spec() { // All trees base on the official example from the vorbis spec section 3.2.1 // but with modifications to under- or overspecify them // underspecified let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3/*, 3*/]); assert!(tree.is_err()); // underspecified let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, /*4,*/ 2, 3, 3]); assert!(tree.is_err()); // overspecified let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3/*]*/,3]); assert!(tree.is_err()); } #[test] fn test_single_entry_huffman_tree() { // Special testing for single entry codebooks, as required by the vorbis spec let tree = VorbisHuffmanTree::load_from_array(&[1]).unwrap(); tree.iter_test(0b0, 1, 0); tree.iter_test(0b1, 1, 0); let tree = VorbisHuffmanTree::load_from_array(&[0, 0, 1, 0]).unwrap(); tree.iter_test(0b0, 1, 2); tree.iter_test(0b1, 1, 2); let tree = VorbisHuffmanTree::load_from_array(&[2]); assert!(tree.is_err()); } #[test] fn test_unordered_huffman_tree() { // Reordered the official example from the vorbis spec section 3.2.1 // // Ensuring that unordered huffman trees work as well is important // because the spec does not disallow them, and unordered // huffman trees appear in "the wild". let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 2, 4, 4, 3, 3]).unwrap(); tree.iter_test(0b00, 2, 0); tree.iter_test(0b0100, 4, 1); tree.iter_test(0b0101, 4, 2); tree.iter_test(0b10, 2, 3); tree.iter_test(0b0110, 4, 4); tree.iter_test(0b0111, 4, 5); tree.iter_test(0b110, 3, 6); tree.iter_test(0b111, 3, 7); } #[test] fn test_extracted_huffman_tree() { // Extracted from a real-life vorbis file. VorbisHuffmanTree::load_from_array(&[ 5, 6, 11, 11, 11, 11, 10, 10, 12, 11, 5, 2, 11, 5, 6, 6, 7, 9, 11, 13, 13, 10, 7, 11, 6, 7, 8, 9, 10, 12, 11, 5, 11, 6, 8, 7, 9, 11, 14, 15, 11, 6, 6, 8, 4, 5, 7, 8, 10,13, 10, 5, 7, 7, 5, 5, 6, 8, 10, 11, 10, 7, 7, 8, 6, 5, 5, 7, 9, 9, 11, 8, 8, 11, 8, 7, 6, 6, 7, 9, 12,11, 10, 13, 9, 9, 7, 7, 7, 9, 11, 13, 12, 15, 12, 11, 9, 8, 8, 8]).unwrap(); } lewton-0.10.2/src/imdct.rs010066400017500001750000000516711376406227100135440ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. // This file is a very close translation of the // implementation of the algorithm from stb_vorbis. use ::header_cached::CachedBlocksizeDerived; fn imdct_step3_iter0_loop(n :usize, e :&mut[f32], i_off :usize, k_off :isize, a :&[f32]) { let mut a_offs = 0; let mut i_offs = i_off; let mut k_offs = i_off as isize + k_off; macro_rules! ee0 { (-$x:expr) => {e[i_offs - ($x as usize)]}; ($x:expr) => {e[i_offs + ($x as usize)]} } macro_rules! ee2 { (-$x:expr) => {e[(k_offs - $x) as usize]}; ($x:expr) => {e[(k_offs + $x) as usize]} } macro_rules! aa { ($x:expr) => {a[a_offs + ($x as usize)]} } assert_eq!((n & 3), 0); for _ in 0 .. n >> 2 { let mut k00_20 = ee0![ 0] - ee2![ 0]; let mut k01_21 = ee0![-1] - ee2![-1]; ee0![ 0] += ee2![ 0]; ee0![-1] += ee2![-1]; ee2![ 0] = k00_20 * aa![0] - k01_21 * aa![1]; ee2![-1] = k01_21 * aa![0] + k00_20 * aa![1]; a_offs += 8; k00_20 = ee0![-2] - ee2![-2]; k01_21 = ee0![-3] - ee2![-3]; ee0![-2] += ee2![-2]; ee0![-3] += ee2![-3]; ee2![-2] = k00_20 * aa![0] - k01_21 * aa![1]; ee2![-3] = k01_21 * aa![0] + k00_20 * aa![1]; a_offs += 8; k00_20 = ee0![-4] - ee2![-4]; k01_21 = ee0![-5] - ee2![-5]; ee0![-4] += ee2![-4]; ee0![-5] += ee2![-5]; ee2![-4] = k00_20 * aa![0] - k01_21 * aa![1]; ee2![-5] = k01_21 * aa![0] + k00_20 * aa![1]; a_offs += 8; k00_20 = ee0![-6] - ee2![-6]; k01_21 = ee0![-7] - ee2![-7]; ee0![-6] += ee2![-6]; ee0![-7] += ee2![-7]; ee2![-6] = k00_20 * aa![0] - k01_21 * aa![1]; ee2![-7] = k01_21 * aa![0] + k00_20 * aa![1]; a_offs += 8; i_offs -= 8; k_offs -= 8; } } fn imdct_step3_inner_r_loop(lim :usize, e :&mut [f32], d0 :usize, k_off :isize, a :&[f32], k1 :usize) { let mut a_offs = 0; let mut d0_offs = d0; let mut k_offs = d0 as isize + k_off; macro_rules! e0 { (-$x:expr) => {e[d0_offs - ($x as usize)]}; ($x:expr) => {e[d0_offs + ($x as usize)]} } macro_rules! e2 { (-$x:expr) => {e[(k_offs - $x) as usize]}; ($x:expr) => {e[(k_offs + $x) as usize]} } macro_rules! aa { ($x:expr) => {a[a_offs + ($x as usize)]} } for _ in 0 .. lim >> 2 { let mut k00_20 = e0![-0] - e2![-0]; let mut k01_21 = e0![-1] - e2![-1]; e0![-0] += e2![-0]; e0![-1] += e2![-1]; e2![-0] = (k00_20) * aa![0] - (k01_21) * aa![1]; e2![-1] = (k01_21) * aa![0] + (k00_20) * aa![1]; a_offs += k1; k00_20 = e0![-2] - e2![-2]; k01_21 = e0![-3] - e2![-3]; e0![-2] += e2![-2]; e0![-3] += e2![-3]; e2![-2] = (k00_20) * aa![0] - (k01_21) * aa![1]; e2![-3] = (k01_21) * aa![0] + (k00_20) * aa![1]; a_offs += k1; k00_20 = e0![-4] - e2![-4]; k01_21 = e0![-5] - e2![-5]; e0![-4] += e2![-4]; e0![-5] += e2![-5]; e2![-4] = (k00_20) * aa![0] - (k01_21) * aa![1]; e2![-5] = (k01_21) * aa![0] + (k00_20) * aa![1]; a_offs += k1; k00_20 = e0![-6] - e2![-6]; k01_21 = e0![-7] - e2![-7]; e0![-6] += e2![-6]; e0![-7] += e2![-7]; e2![-6] = (k00_20) * aa![0] - (k01_21) * aa![1]; e2![-7] = (k01_21) * aa![0] + (k00_20) * aa![1]; d0_offs -= 8; k_offs -= 8; a_offs += k1; } } fn imdct_step3_inner_s_loop(n :usize, e :&mut [f32], i_off :usize, k_off :isize, a :&[f32], a_off :usize, k0 :usize) { let a0 = a[0]; let a1 = a[0+1]; let a2 = a[0+a_off]; let a3 = a[0+a_off+1]; let a4 = a[0+a_off*2+0]; let a5 = a[0+a_off*2+1]; let a6 = a[0+a_off*3+0]; let a7 = a[0+a_off*3+1]; let mut i_offs = i_off; let mut k_offs = (i_off as isize + k_off) as usize; macro_rules! ee0 { (-$x:expr) => {e[i_offs - ($x as usize)]}; ($x:expr) => {e[i_offs + ($x as usize)]} } macro_rules! ee2 { (-$x:expr) => {e[k_offs - ($x as usize)]}; ($x:expr) => {e[k_offs + ($x as usize)]} } let mut i = 0; loop { let mut k00 = ee0![ 0] - ee2![ 0]; let mut k11 = ee0![-1] - ee2![-1]; ee0![ 0] = ee0![ 0] + ee2![ 0]; ee0![-1] = ee0![-1] + ee2![-1]; ee2![ 0] = (k00) * a0 - (k11) * a1; ee2![-1] = (k11) * a0 + (k00) * a1; k00 = ee0![-2] - ee2![-2]; k11 = ee0![-3] - ee2![-3]; ee0![-2] = ee0![-2] + ee2![-2]; ee0![-3] = ee0![-3] + ee2![-3]; ee2![-2] = (k00) * a2 - (k11) * a3; ee2![-3] = (k11) * a2 + (k00) * a3; k00 = ee0![-4] - ee2![-4]; k11 = ee0![-5] - ee2![-5]; ee0![-4] = ee0![-4] + ee2![-4]; ee0![-5] = ee0![-5] + ee2![-5]; ee2![-4] = (k00) * a4 - (k11) * a5; ee2![-5] = (k11) * a4 + (k00) * a5; k00 = ee0![-6] - ee2![-6]; k11 = ee0![-7] - ee2![-7]; ee0![-6] = ee0![-6] + ee2![-6]; ee0![-7] = ee0![-7] + ee2![-7]; ee2![-6] = (k00) * a6 - (k11) * a7; ee2![-7] = (k11) * a6 + (k00) * a7; i += 1; // we have this check instead of a for loop // over an iterator because otherwise we // overflow. if i >= n { break; } i_offs -= k0; k_offs -= k0; } } #[inline] fn iter_54(zm7 :&mut [f32]) { // difference from stb_vorbis implementation: // zm7 points to z minus 7 // (Rust disallows negative indices) let k00 = zm7[7] - zm7[3]; let y0 = zm7[7] + zm7[3]; let y2 = zm7[5] + zm7[1]; let k22 = zm7[5] - zm7[1]; zm7[7] = y0 + y2; // z0 + z4 + z2 + z6 zm7[5] = y0 - y2; // z0 + z4 - z2 - z6 // done with y0,y2 let k33 = zm7[4] - zm7[0]; zm7[3] = k00 + k33; // z0 - z4 + z3 - z7 zm7[1] = k00 - k33; // z0 - z4 - z3 + z7 // done with k33 let k11 = zm7[6] - zm7[2]; let y1 = zm7[6] + zm7[2]; let y3 = zm7[4] + zm7[0]; zm7[6] = y1 + y3; // z1 + z5 + z3 + z7 zm7[4] = y1 - y3; // z1 + z5 - z3 - z7 zm7[2] = k11 - k22; // z1 - z5 + z2 - z6 zm7[0] = k11 + k22; // z1 - z5 - z2 + z6 } fn imdct_step3_inner_s_loop_ld654(n :usize, e :&mut [f32], i_off :usize, a :&[f32], base_n :usize) { let a_off = base_n >> 3; let a2 = a[a_off]; let mut z_offs = i_off; let basep16 = i_off - 16 * (n - 1 as usize); macro_rules! z { (-$x:expr) => {e[z_offs - ($x as usize)]} } loop { let mut k00 = z![-0] - z![-8]; let mut k11 = z![-1] - z![-9]; z![-0] = z![-0] + z![-8]; z![-1] = z![-1] + z![-9]; z![-8] = k00; z![-9] = k11; k00 = z![ -2] - z![-10]; k11 = z![ -3] - z![-11]; z![ -2] = z![ -2] + z![-10]; z![ -3] = z![ -3] + z![-11]; z![-10] = (k00+k11) * a2; z![-11] = (k11-k00) * a2; k00 = z![-12] - z![ -4]; // reverse to avoid a unary negation k11 = z![ -5] - z![-13]; z![ -4] = z![ -4] + z![-12]; z![ -5] = z![ -5] + z![-13]; z![-12] = k11; z![-13] = k00; k00 = z![-14] - z![ -6]; // reverse to avoid a unary negation k11 = z![ -7] - z![-15]; z![ -6] = z![ -6] + z![-14]; z![ -7] = z![ -7] + z![-15]; z![-14] = (k00+k11) * a2; z![-15] = (k00-k11) * a2; iter_54(e.split_at_mut(z_offs - 7).1); iter_54(e.split_at_mut(z_offs - 7 - 8).1); // We need to compare with basep16 here // in order to prevent a possible overflow // in calculation of base, and in calculation // of z_offs. if z_offs <= basep16 { break; } z_offs -= 16; } } #[allow(dead_code)] pub fn inverse_mdct(cached_bd :&CachedBlocksizeDerived, buffer :&mut [f32], bs :u8) { let n = buffer.len(); // Pre-condition. assert_eq!(n, 1 << bs); let n2 = n >> 1; let n4 = n >> 2; let n8 = n >> 3; // TODO later on we might want to do Vec::with_capacity here, // and use buf2.push everywhere... let mut buf2 :Vec = vec![0.0; n2]; let ctf = &cached_bd.twiddle_factors; let a :&[f32] = &ctf.a; let b :&[f32] = &ctf.b; let c :&[f32] = &ctf.c; macro_rules! break_if_sub_overflows { ($i:ident, $x:expr) => { $i = match $i.checked_sub($x) { Some(v) => v, None => break, }; } } // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' in stb_vorbis original. // kernel from paper // merged: // copy and reflect spectral data // step 0 // note that it turns out that the items added together during // this step are, in fact, being added to themselves (as reflected // by step 0). inexplicable inefficiency! this became obvious // once I combined the passes. // so there's a missing 'times 2' here (for adding X to itself). // this propogates through linearly to the end, where the numbers // are 1/2 too small, and need to be compensated for. { let mut a_offs = 0; let mut d_offs = n2 - 2; let mut e_offs = 0; let e_stop = n2; macro_rules! d { ($x:expr) => {buf2[d_offs + ($x as usize)]} } macro_rules! aa { ($x:expr) => {a[a_offs + ($x as usize)]} } macro_rules! e { ($x:expr) => {buffer[e_offs + ($x as usize)]} } // TODO replace the while with a for once step_by on iterators // is stabilized while e_offs != e_stop { d![1] = e![0] * aa![0] - e![2]*aa![1]; d![0] = e![0] * aa![1] + e![2]*aa![0]; d_offs -= 2; a_offs += 2; e_offs += 4; } e_offs = n2 - 3; loop { d![1] = -e![2] * aa![0] - -e![0]*aa![1]; d![0] = -e![2] * aa![1] + -e![0]*aa![0]; break_if_sub_overflows!(d_offs, 2); a_offs += 2; e_offs -= 4; } } { // now we use symbolic names for these, so that we can // possibly swap their meaning as we change which operations // are in place let u = &mut *buffer; let v = &mut *buf2; // step 2 (paper output is w, now u) // this could be in place, but the data ends up in the wrong // place... _somebody_'s got to swap it, so this is nominated { let mut a_offs = n2 - 8; let mut d0_offs = n4; let mut d1_offs = 0; let mut e0_offs = n4; let mut e1_offs = 0; macro_rules! aa { ($x:expr) => {a[a_offs + ($x as usize)]} } macro_rules! d0 { ($x:expr) => {u[d0_offs + ($x as usize)]} } macro_rules! d1 { ($x:expr) => {u[d1_offs + ($x as usize)]} } macro_rules! e0 { ($x:expr) => {v[e0_offs + ($x as usize)]} } macro_rules! e1 { ($x:expr) => {v[e1_offs + ($x as usize)]} } loop { let mut v41_21 = e0![1] - e1![1]; let mut v40_20 = e0![0] - e1![0]; d0![1] = e0![1] + e1![1]; d0![0] = e0![0] + e1![0]; d1![1] = v41_21*aa![4] - v40_20*aa![5]; d1![0] = v40_20*aa![4] + v41_21*aa![5]; v41_21 = e0![3] - e1![3]; v40_20 = e0![2] - e1![2]; d0![3] = e0![3] + e1![3]; d0![2] = e0![2] + e1![2]; d1![3] = v41_21*aa![0] - v40_20*aa![1]; d1![2] = v40_20*aa![0] + v41_21*aa![1]; break_if_sub_overflows!(a_offs, 8); d0_offs += 4; d1_offs += 4; e0_offs += 4; e1_offs += 4; } } // step 3 let ld = bs as usize; // optimized step 3: // the original step3 loop can be nested r inside s or s inside r; // it's written originally as s inside r, but this is dumb when r // iterates many times, and s few. So I have two copies of it and // switch between them halfway. // this is iteration 0 of step 3 imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n as isize >> 3), a); imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n as isize >> 3), a); // this is iteration 1 of step 3 imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n as isize >> 4), a, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n as isize >> 4), a, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n as isize >> 4), a, 16); imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n as isize >> 4), a, 16); for l in 2 .. (ld - 3) >> 1 { let k0 = n >> (l + 2); let k0_2 = k0 as isize >> 1; let lim = 1 << (l+1); for i in 0 .. lim { imdct_step3_inner_r_loop(n >> (l + 4), u, n2-1 - k0*i, -k0_2, a, 1 << (l+3)); } } for l in (ld - 3) >> 1 .. ld - 6 { let k0 = n >> (l + 2); let k1 = 1 << (l + 3); let k0_2 = k0 as isize >> 1; let rlim = n >> (l + 6); let lim = 1 << (l + 1); let mut i_off = n2 - 1; let mut a_off = 0; for _ in 0 .. rlim { let a0 = a.split_at(a_off).1; imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, a0, k1, k0); a_off += k1 * 4; i_off -= 8; } } // iterations with count: // ld-6,-5,-4 all interleaved together // the big win comes from getting rid of needless flops // due to the constants on pass 5 & 4 being all 1 and 0; // combining them to be simultaneous to improve cache made little difference imdct_step3_inner_s_loop_ld654(n >> 5, u, n2 - 1, a, n); // output is u // step 4, 5, and 6 // cannot be in-place because of step 5 { let bitrev_vec = &cached_bd.bitrev; // weirdly, I'd have thought reading sequentially and writing // erratically would have been better than vice-versa, but in // fact that's not what my testing showed. (That is, with // j = bitreverse(i), do you read i and write j, or read j and write i.) let mut d0_offs = n4 - 4; let mut d1_offs = n2 - 4; let mut bitrev_offs = 0; macro_rules! d0 { ($x:expr) => {v[d0_offs + ($x as usize)]} } macro_rules! d1 { ($x:expr) => {v[d1_offs + ($x as usize)]} } macro_rules! bitrev { ($x:expr) => {bitrev_vec[bitrev_offs + ($x as usize)]} } loop { let mut k4 = bitrev![0] as usize; d1![3] = u[k4 + 0]; d1![2] = u[k4 + 1]; d0![3] = u[k4 + 2]; d0![2] = u[k4 + 3]; k4 = bitrev![1] as usize; d1![1] = u[k4 + 0]; d1![0] = u[k4 + 1]; d0![1] = u[k4 + 2]; d0![0] = u[k4 + 3]; break_if_sub_overflows!(d0_offs, 4); d1_offs -= 4; bitrev_offs += 2; } } // (paper output is u, now v) // step 7 (paper output is v, now v) // this is now in place { let mut c_offs = 0; let mut d_offs = 0; let mut e_offs = n2 - 4; macro_rules! cc { ($x:expr) => {c[c_offs + ($x as usize)]} } macro_rules! d { ($x:expr) => {v[d_offs + ($x as usize)]} } macro_rules! e { ($x:expr) => {v[e_offs + ($x as usize)]} } while d_offs < e_offs { let mut a02 = d![0] - e![2]; let mut a11 = d![1] + e![3]; let mut b0 = cc![1]*a02 + cc![0]*a11; let mut b1 = cc![1]*a11 - cc![0]*a02; let mut b2 = d![0] + e![ 2]; let mut b3 = d![1] - e![ 3]; d![0] = b2 + b0; d![1] = b3 + b1; e![2] = b2 - b0; e![3] = b1 - b3; a02 = d![2] - e![0]; a11 = d![3] + e![1]; b0 = cc![3]*a02 + cc![2]*a11; b1 = cc![3]*a11 - cc![2]*a02; b2 = d![2] + e![ 0]; b3 = d![3] - e![ 1]; d![2] = b2 + b0; d![3] = b3 + b1; e![0] = b2 - b0; e![1] = b1 - b3; c_offs += 4; d_offs += 4; e_offs -= 4; } } } // step 8+decode (paper output is X, now buffer) // this generates pairs of data a la 8 and pushes them directly through // the decode kernel (pushing rather than pulling) to avoid having // to make another pass later // this cannot POSSIBLY be in place, so we refer to the buffers directly { let mut d0_offs = 0; let mut d1_offs = n2 - 4; let mut d2_offs = n2; let mut d3_offs = n - 4; let mut b_offs = n2 - 8; let mut e_offs = n2 - 8; macro_rules! d0 { ($x:expr) => {buffer[d0_offs + ($x as usize)]} } macro_rules! d1 { ($x:expr) => {buffer[d1_offs + ($x as usize)]} } macro_rules! d2 { ($x:expr) => {buffer[d2_offs + ($x as usize)]} } macro_rules! d3 { ($x:expr) => {buffer[d3_offs + ($x as usize)]} } macro_rules! b { ($x:expr) => {b[b_offs + ($x as usize)]} } macro_rules! e { ($x:expr) => {buf2[e_offs + ($x as usize)]} } loop { let mut p3 = e![6]*b![7] - e![7]*b![6]; let mut p2 = -e![6]*b![6] - e![7]*b![7]; d0![0] = p3; d1![3] = - p3; d2![0] = p2; d3![3] = p2; let mut p1 = e![4]*b![5] - e![5]*b![4]; let mut p0 = -e![4]*b![4] - e![5]*b![5]; d0![1] = p1; d1![2] = - p1; d2![1] = p0; d3![2] = p0; p3 = e![2]*b![3] - e![3]*b![2]; p2 = -e![2]*b![2] - e![3]*b![3]; d0![2] = p3; d1![1] = - p3; d2![2] = p2; d3![1] = p2; p1 = e![0]*b![1] - e![1]*b![0]; p0 = -e![0]*b![0] - e![1]*b![1]; d0![3] = p1; d1![0] = - p1; d2![3] = p0; d3![0] = p0; break_if_sub_overflows!(e_offs, 8); b_offs -= 8; d0_offs += 4; d2_offs += 4; d1_offs -= 4; d3_offs -= 4; } } } #[allow(dead_code)] pub fn inverse_mdct_naive(cached_bd :&CachedBlocksizeDerived, buffer :&mut[f32]) { let n = buffer.len(); let n2 = n >> 1; let n4 = n >> 2; let n8 = n >> 3; let n3_4 = n - n4; let mut u = [0.0; 1 << 13]; let mut xa = [0.0; 1 << 13]; let mut v = [0.0; 1 << 13]; let mut w = [0.0; 1 << 13]; // retrieve the cached twiddle factors let ctf = &cached_bd.twiddle_factors; let a :&[f32] = &ctf.a; let b :&[f32] = &ctf.b; let c :&[f32] = &ctf.c; // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" // Note there are bugs in that pseudocode, presumably due to them attempting // to rename the arrays nicely rather than representing the way their actual // implementation bounces buffers back and forth. As a result, even in the // "some formulars corrected" version, a direct implementation fails. These // are noted below as "paper bug". // copy and reflect spectral data for k in 0 .. n2 { u[k] = buffer[k]; } for k in n2 .. n { u[k] = -buffer[n - k - 1]; } let mut k2 = 0; let mut k4 = 0; // kernel from paper // step 1 while k2 < n2 { // n4 iterations v[n-k4-1] = (u[k4] - u[n-k4-1]) * a[k2] - (u[k4+2] - u[n-k4-3])*a[k2+1]; v[n-k4-3] = (u[k4] - u[n-k4-1]) * a[k2+1] + (u[k4+2] - u[n-k4-3])*a[k2]; k2 += 2; k4 += 4; } // step 2 k4 = 0; while k4 < n2 { // n8 iterations w[n2+3+k4] = v[n2+3+k4] + v[k4+3]; w[n2+1+k4] = v[n2+1+k4] + v[k4+1]; w[k4+3] = (v[n2+3+k4] - v[k4+3])*a[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*a[n2-3-k4]; w[k4+1] = (v[n2+1+k4] - v[k4+1])*a[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*a[n2-3-k4]; k4 += 4; } // step 3 let ld :usize = (::ilog(n as u64) - 1) as usize; for l in 0 .. ld - 3 { let k0 = n >> (l+2); let k1 = 1 << (l+3); let rlim = n >> (l+4); let slim = 1 << (l+1); let mut r4 = 0; for r in 0 .. rlim { let mut s2 = 0; for _ in 0 .. slim { u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4]; u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4]; u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * a[r*k1] - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * a[r*k1+1]; u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * a[r*k1] + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * a[r*k1+1]; s2 += 2; } r4 += 4; } if l+1 < ld-3 { // paper bug: ping-ponging of u&w here is omitted w.copy_from_slice(&u); } } // step 4 for i in 0 .. n8 { let j = (::bit_reverse(i as u32) >> (32-ld+3)) as usize; assert!(j < n8); if i == j { // paper bug: original code probably swapped in place; if copying, // need to directly copy in this case let ii = i << 3; v[ii+1] = u[ii+1]; v[ii+3] = u[ii+3]; v[ii+5] = u[ii+5]; v[ii+7] = u[ii+7]; } else if i < j { let ii = i << 3; let j8 = j << 3; v[j8+1] = u[ii+1]; v[ii+1] = u[j8 + 1]; v[j8+3] = u[ii+3]; v[ii+3] = u[j8 + 3]; v[j8+5] = u[ii+5]; v[ii+5] = u[j8 + 5]; v[j8+7] = u[ii+7]; v[ii+7] = u[j8 + 7]; } } // step 5 for k in 0 .. n2 { w[k] = v[k*2+1]; } // step 6 let mut k2 = 0; let mut k4 = 0; while k2 < n4 { // n8 iterations u[n-1-k2] = w[k4]; u[n-2-k2] = w[k4+1]; u[n3_4 - 1 - k2] = w[k4+2]; u[n3_4 - 2 - k2] = w[k4+3]; k2 += 2; k4 += 4; } // step 7 k2 = 0; while k2 < n4 { // n8 iterations v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + c[k2+1]*(u[n2+k2]-u[n-2-k2]) + c[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2.0; v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - c[k2+1]*(u[n2+k2]-u[n-2-k2]) - c[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2.0; v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + c[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - c[k2]*(u[n2+k2]-u[n-2-k2]))/2.0; v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + c[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - c[k2]*(u[n2+k2]-u[n-2-k2]))/2.0; k2 += 2; } // step 8 k2 = 0; for k in 0 .. n4 { xa[k] = v[k2+n2]*b[k2 ] + v[k2+1+n2]*b[k2+1]; xa[n2-1-k] = v[k2+n2]*b[k2+1] - v[k2+1+n2]*b[k2 ]; k2 += 2; } // decode kernel to output for i in 0 .. n4 { buffer[i] = xa[i + n4]; } for i in n4 .. n3_4 { buffer[i] = -xa[n3_4 - i - 1]; } for i in n3_4 .. n { buffer[i] = -xa[i - n3_4]; } } #[cfg(test)] #[test] fn test_imdct_naive() { use imdct_test::*; let mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1); let cbd = CachedBlocksizeDerived::from_blocksize(8); inverse_mdct_naive(&cbd, &mut arr_1); let mismatches = fuzzy_compare_array( &arr_1, &IMDCT_OUTPUT_TEST_ARR_1, 0.00005, true); let mismatches_limit = 0; if mismatches > mismatches_limit { panic!("Numer of mismatches {} was larger than limit of {}", mismatches, mismatches_limit); } } #[cfg(test)] #[test] fn test_imdct() { use imdct_test::*; let mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1); let blocksize = 8; let cbd = CachedBlocksizeDerived::from_blocksize(blocksize); inverse_mdct(&cbd, &mut arr_1, blocksize); let mismatches = fuzzy_compare_array( &arr_1, &IMDCT_OUTPUT_TEST_ARR_1, 0.00005, true); let mismatches_limit = 0; if mismatches > mismatches_limit { panic!("Numer of mismatches {} was larger than limit of {}", mismatches, mismatches_limit); } } lewton-0.10.2/src/imdct_test.rs010066400017500001750000001172131316772620700146010ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. #![allow(dead_code)] pub static IMDCT_INPUT_TEST_ARR_1 :[f32; 128] = [-0.01894, -0.10670, 0.51740, 0.39750, 0.03894, 0.00692, 0.00000, 0.00369, 0.00092, -0.00143, -0.00056, 0.00087, 0.00067, -0.00063, -0.00056, 0.00052, 0.00046, -0.00043, -0.00041, 0.00036, 0.00034, -0.00030, -0.00028, 0.00025, 0.00025, -0.00012, -0.00022, 0.00010, 0.00019, -0.00010, -0.00018, 0.00008, 0.00016, -0.00007, -0.00015, 0.00007, 0.00013, -0.00006, -0.00012, 0.00006, 0.00011, -0.00005, -0.00010, 0.00005, 0.00009, -0.00004, -0.00008, 0.00004, 0.00008, 0.00000, -0.00007, 0.00000, 0.00007, 0.00000, -0.00007, 0.00000, 0.00007, 0.00000, -0.00007, 0.00000, 0.00007, 0.00000, -0.00006, 0.00000, 0.00006, 0.00000, -0.00006, 0.00000, 0.00006, 0.00000, -0.00005, 0.00000, 0.00005, 0.00000, -0.00003, 0.00000, 0.00003, 0.00000, -0.00003, 0.00000, 0.00003, 0.00000, -0.00003, 0.00000, 0.00003, 0.00000, -0.00003, 0.00000, 0.00004, 0.00000, -0.00004, 0.00000, 0.00005, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000]; pub static IMDCT_OUTPUT_TEST_ARR_1 :[f32; 256] = [ 0.03325, 0.07520, 0.11729, 0.15753, 0.19588, 0.23308, 0.26823, 0.30140, 0.33234, 0.36078, 0.38742, 0.41169, 0.43321, 0.45243, 0.46889, 0.48269, 0.49426, 0.50325, 0.50983, 0.51412, 0.51613, 0.51621, 0.51417, 0.51004, 0.50417, 0.49634, 0.48682, 0.47595, 0.46349, 0.44974, 0.43492, 0.41903, 0.40238, 0.38495, 0.36682, 0.34831, 0.32932, 0.31015, 0.29104, 0.27183, 0.25285, 0.23427, 0.21602, 0.19839, 0.18134, 0.16489, 0.14925, 0.13434, 0.12030, 0.10721, 0.09486, 0.08348, 0.07306, 0.06339, 0.05463, 0.04662, 0.03925, 0.03264, 0.02655, 0.02098, 0.01586, 0.01098, 0.00648, 0.00219, -0.00219, -0.00648, -0.01098, -0.01586, -0.02098, -0.02655, -0.03264, -0.03925, -0.04662, -0.05463, -0.06339, -0.07306, -0.08348, -0.09486, -0.10721, -0.12030, -0.13434, -0.14925, -0.16489, -0.18134, -0.19839, -0.21602, -0.23427, -0.25285, -0.27183, -0.29104, -0.31015, -0.32932, -0.34831, -0.36682, -0.38495, -0.40238, -0.41903, -0.43492, -0.44974, -0.46349, -0.47595, -0.48682, -0.49634, -0.50417, -0.51004, -0.51417, -0.51621, -0.51613, -0.51412, -0.50983, -0.50325, -0.49426, -0.48269, -0.46889, -0.45243, -0.43321, -0.41169, -0.38742, -0.36078, -0.33234, -0.30140, -0.26823, -0.23308, -0.19588, -0.15753, -0.11729, -0.07520, -0.03325, 0.01147, 0.06175, 0.11352, 0.16419, 0.21479, 0.26472, 0.31382, 0.36215, 0.40885, 0.45420, 0.49798, 0.53953, 0.57931, 0.61680, 0.65136, 0.68325, 0.71206, 0.73749, 0.75955, 0.77780, 0.79226, 0.80284, 0.80927, 0.81177, 0.80999, 0.80374, 0.79336, 0.77856, 0.75936, 0.73598, 0.70826, 0.67643, 0.64070, 0.60110, 0.55796, 0.51130, 0.46132, 0.40853, 0.35296, 0.29496, 0.23502, 0.17323, 0.11014, 0.04621, -0.01834, -0.08299, -0.14746, -0.21136, -0.27409, -0.33545, -0.39494, -0.45208, -0.50668, -0.55817, -0.60612, -0.65041, -0.69058, -0.72643, -0.75773, -0.78409, -0.80548, -0.82165, -0.83246, -0.83802, -0.83802, -0.83246, -0.82165, -0.80548, -0.78409, -0.75773, -0.72643, -0.69058, -0.65041, -0.60612, -0.55817, -0.50668, -0.45208, -0.39494, -0.33545, -0.27409, -0.21136, -0.14746, -0.08299, -0.01834, 0.04621, 0.11014, 0.17323, 0.23502, 0.29496, 0.35296, 0.40853, 0.46132, 0.51130, 0.55796, 0.60110, 0.64070, 0.67643, 0.70826, 0.73598, 0.75936, 0.77856, 0.79336, 0.80374, 0.80999, 0.81177, 0.80927, 0.80284, 0.79226, 0.77780, 0.75955, 0.73749, 0.71206, 0.68325, 0.65136, 0.61680, 0.57931, 0.53953, 0.49798, 0.45420, 0.40885, 0.36215, 0.31382, 0.26472, 0.21479, 0.16419, 0.11352, 0.06175, 0.01147]; pub static IMDCT_INPUT_TEST_ARR_2 :[f32; 128] = [ 0.07109, 0.29427, 0.58470, -0.36304, 0.05009, -0.01145, 0.00184, 0.00063, -0.00020, -0.00018, 0.00015, 0.00013, -0.00011, -0.00009, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000]; pub static IMDCT_OUTPUT_TEST_ARR_2 :[f32; 256] = [-0.78862, -0.79274, -0.79359, -0.79110, -0.78522, -0.77592, -0.76317, -0.74696, -0.72731, -0.70422, -0.67775, -0.64795, -0.61489, -0.57868, -0.53943, -0.49729, -0.45242, -0.40500, -0.35524, -0.30338, -0.24966, -0.19435, -0.13774, -0.08012, -0.02181, 0.03686, 0.09556, 0.15395, 0.21166, 0.26837, 0.32370, 0.37732, 0.42887, 0.47801, 0.52442, 0.56776, 0.60774, 0.64406, 0.67645, 0.70467, 0.72849, 0.74771, 0.76217, 0.77173, 0.77628, 0.77576, 0.77013, 0.75940, 0.74361, 0.72283, 0.69717, 0.66679, 0.63188, 0.59264, 0.54935, 0.50227, 0.45173, 0.39806, 0.34162, 0.28282, 0.22204, 0.15972, 0.09628, 0.03217, -0.03217, -0.09628, -0.15972, -0.22204, -0.28282, -0.34162, -0.39806, -0.45173, -0.50227, -0.54935, -0.59264, -0.63188, -0.66679, -0.69717, -0.72283, -0.74361, -0.75940, -0.77013, -0.77576, -0.77628, -0.77173, -0.76217, -0.74771, -0.72849, -0.70467, -0.67645, -0.64406, -0.60774, -0.56776, -0.52442, -0.47801, -0.42887, -0.37732, -0.32370, -0.26837, -0.21166, -0.15395, -0.09556, -0.03686, 0.02181, 0.08012, 0.13774, 0.19435, 0.24966, 0.30338, 0.35524, 0.40500, 0.45242, 0.49729, 0.53943, 0.57868, 0.61489, 0.64795, 0.67775, 0.70422, 0.72731, 0.74696, 0.76317, 0.77592, 0.78522, 0.79110, 0.79359, 0.79274, 0.78862, 0.78129, 0.77084, 0.75738, 0.74100, 0.72184, 0.70003, 0.67572, 0.64906, 0.62022, 0.58938, 0.55672, 0.52243, 0.48671, 0.44973, 0.41171, 0.37283, 0.33328, 0.29325, 0.25290, 0.21241, 0.17195, 0.13166, 0.09170, 0.05219, 0.01327, -0.02493, -0.06232, -0.09878, -0.13422, -0.16855, -0.20169, -0.23358, -0.26416, -0.29339, -0.32122, -0.34763, -0.37261, -0.39615, -0.41827, -0.43897, -0.45828, -0.47624, -0.49288, -0.50825, -0.52239, -0.53536, -0.54722, -0.55801, -0.56779, -0.57662, -0.58455, -0.59163, -0.59793, -0.60348, -0.60833, -0.61255, -0.61616, -0.61922, -0.62176, -0.62383, -0.62543, -0.62662, -0.62740, -0.62778, -0.62778, -0.62740, -0.62662, -0.62543, -0.62383, -0.62176, -0.61922, -0.61616, -0.61255, -0.60833, -0.60348, -0.59793, -0.59163, -0.58455, -0.57662, -0.56779, -0.55801, -0.54722, -0.53536, -0.52239, -0.50825, -0.49288, -0.47624, -0.45828, -0.43897, -0.41827, -0.39615, -0.37261, -0.34763, -0.32122, -0.29339, -0.26416, -0.23358, -0.20169, -0.16855, -0.13422, -0.09878, -0.06232, -0.02493, 0.01327, 0.05219, 0.09170, 0.13166, 0.17195, 0.21241, 0.25290, 0.29325, 0.33328, 0.37283, 0.41171, 0.44973, 0.48671, 0.52243, 0.55672, 0.58938, 0.62022, 0.64906, 0.67572, 0.70003, 0.72184, 0.74100, 0.75738, 0.77084, 0.78129]; pub static IMDCT_INPUT_TEST_ARR_3 :[f32; 1024] = [-0.00325, 0.00916, -0.01147, 0.00942, -0.00442, 0.00059, 0.00000, 0.00430, -0.01291, 0.02373, -0.03052, 0.03141, -0.02273, 0.00975, 0.00000, 0.00836, -0.04179, 0.11284, -0.20060, 0.25075, -0.21732, 0.10448, 0.00000, -0.05433, 0.05886, -0.03806, 0.01525, 0.00000, -0.00474, 0.00209, 0.00184, -0.00488, 0.00573, -0.00379, 0.00111, 0.00209, -0.00277, 0.00325, -0.00215, 0.00126, 0.00000, 0.00000, -0.00043, 0.00153, -0.00202, 0.00208, -0.00157, 0.00079, -0.00026, 0.00000, 0.00000, 0.00023, -0.00046, 0.00065, -0.00043, 0.00020, 0.00020, -0.00038, 0.00057, -0.00036, 0.00018, 0.00000, 0.00000, 0.00000, 0.00016, -0.00032, 0.00030, -0.00030, 0.00014, 0.00014, -0.00013, 0.00013, 0.00000, 0.00000, 0.00012, -0.00012, 0.00000, 0.00011, -0.00022, 0.00020, -0.00010, 0.00000, 0.00010, -0.00009, 0.00000, 0.00000, -0.00008, 0.00008, -0.00008, 0.00000, 0.00007, -0.00014, 0.00007, -0.00007, 0.00000, 0.00007, 0.00000, 0.00000, 0.00006, -0.00012, 0.00006, -0.00006, 0.00000, 0.00005, -0.00005, 0.00005, 0.00000, -0.00005, 0.00005, 0.00000, -0.00005, 0.00005, -0.00009, 0.00004, 0.00000, -0.00004, 0.00004, -0.00004, 0.00000, 0.00004, -0.00004, 0.00004, 0.00000, -0.00004, 0.00007, -0.00003, 0.00003, 0.00000, -0.00003, 0.00003, 0.00000, -0.00003, 0.00003, -0.00003, 0.00003, 0.00000, -0.00003, 0.00003, -0.00003, 0.00000, 0.00003, -0.00003, 0.00000, 0.00000, -0.00002, 0.00005, -0.00002, 0.00000, 0.00002, -0.00002, 0.00002, 0.00000, -0.00002, 0.00002, -0.00002, 0.00000, 0.00002, -0.00004, 0.00004, -0.00002, 0.00000, 0.00002, -0.00002, 0.00000, 0.00002, -0.00002, 0.00002, -0.00002, 0.00000, 0.00001, -0.00003, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00002, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00002, -0.00002, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00002, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00002, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, 0.00000, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00002, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00000, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, 0.00000, 0.00001, -0.00001, 0.00000, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, 0.00000, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00000, -0.00001, 0.00001, 0.00000, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00000, -0.00001, 0.00001, 0.00000, -0.00001, 0.00001, -0.00001, 0.00000, 0.00001, -0.00001, 0.00001, 0.00000, 0.00000, 0.00001, -0.00001, 0.00000, 0.00000, -0.00001, 0.00001, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, -0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000]; pub static IMDCT_OUTPUT_TEST_ARR_3 :[f32; 2048] = [ 0.00454, 0.00669, 0.00892, 0.01121, 0.01351, 0.01581, 0.01811, 0.02041, 0.02267, 0.02487, 0.02702, 0.02908, 0.03102, 0.03282, 0.03452, 0.03617, 0.03774, 0.03921, 0.04058, 0.04183, 0.04296, 0.04392, 0.04472, 0.04535, 0.04582, 0.04612, 0.04624, 0.04619, 0.04598, 0.04560, 0.04503, 0.04427, 0.04332, 0.04220, 0.04090, 0.03945, 0.03782, 0.03599, 0.03400, 0.03185, 0.02955, 0.02709, 0.02447, 0.02172, 0.01883, 0.01580, 0.01262, 0.00933, 0.00593, 0.00242, -0.00120, -0.00491, -0.00870, -0.01258, -0.01650, -0.02046, -0.02445, -0.02847, -0.03246, -0.03641, -0.04032, -0.04420, -0.04798, -0.05160, -0.05506, -0.05837, -0.06151, -0.06445, -0.06721, -0.06980, -0.07217, -0.07432, -0.07628, -0.07803, -0.07947, -0.08055, -0.08134, -0.08185, -0.08203, -0.08187, -0.08141, -0.08063, -0.07948, -0.07797, -0.07616, -0.07403, -0.07150, -0.06857, -0.06532, -0.06174, -0.05777, -0.05342, -0.04875, -0.04380, -0.03852, -0.03292, -0.02705, -0.02093, -0.01456, -0.00799, -0.00126, 0.00564, 0.01270, 0.01986, 0.02705, 0.03427, 0.04154, 0.04878, 0.05595, 0.06301, 0.06997, 0.07678, 0.08341, 0.08986, 0.09613, 0.10215, 0.10790, 0.11335, 0.11850, 0.12329, 0.12768, 0.13165, 0.13521, 0.13831, 0.14092, 0.14300, 0.14456, 0.14557, 0.14601, 0.14585, 0.14512, 0.14380, 0.14184, 0.13919, 0.13590, 0.13201, 0.12753, 0.12241, 0.11665, 0.11028, 0.10334, 0.09586, 0.08786, 0.07935, 0.07030, 0.06069, 0.05056, 0.03998, 0.02900, 0.01763, 0.00587, -0.00621, -0.01856, -0.03113, -0.04387, -0.05675, -0.06972, -0.08274, -0.09573, -0.10864, -0.12143, -0.13403, -0.14638, -0.15842, -0.17010, -0.18136, -0.19213, -0.20237, -0.21201, -0.22098, -0.22922, -0.23671, -0.24342, -0.24927, -0.25419, -0.25819, -0.26122, -0.26319, -0.26408, -0.26389, -0.26263, -0.26023, -0.25666, -0.25195, -0.24610, -0.23908, -0.23088, -0.22152, -0.21101, -0.19934, -0.18655, -0.17271, -0.15782, -0.14189, -0.12498, -0.10722, -0.08867, -0.06931, -0.04915, -0.02828, -0.00678, 0.01522, 0.03764, 0.06037, 0.08332, 0.10640, 0.12956, 0.15278, 0.17592, 0.19880, 0.22131, 0.24344, 0.26512, 0.28620, 0.30652, 0.32606, 0.34475, 0.36246, 0.37904, 0.39443, 0.40859, 0.42139, 0.43269, 0.44243, 0.45058, 0.45704, 0.46171, 0.46456, 0.46555, 0.46464, 0.46175, 0.45689, 0.45002, 0.44112, 0.43016, 0.41715, 0.40211, 0.38504, 0.36597, 0.34494, 0.32197, 0.29714, 0.27052, 0.24215, 0.21211, 0.18049, 0.14736, 0.11283, 0.07703, 0.04012, 0.00221, -0.03663, -0.07619, -0.11623, -0.15668, -0.19747, -0.23835, -0.27906, -0.31956, -0.35988, -0.39967, -0.43840, -0.47617, -0.51362, -0.55083, -0.58678, -0.62029, -0.65106, -0.67937, -0.70523, -0.72830, -0.74839, -0.76555, -0.77976, -0.79086, -0.79878, -0.80358, -0.80526, -0.80376, -0.79907, -0.79124, -0.78031, -0.76627, -0.74919, -0.72918, -0.70631, -0.68065, -0.65230, -0.62140, -0.58808, -0.55245, -0.51464, -0.47484, -0.43321, -0.38990, -0.34508, -0.29891, -0.25161, -0.20336, -0.15431, -0.10469, -0.05472, -0.00459, 0.04555, 0.09552, 0.14508, 0.19401, 0.24218, 0.28943, 0.33551, 0.38019, 0.42336, 0.46488, 0.50457, 0.54222, 0.57769, 0.61091, 0.64174, 0.67006, 0.69575, 0.71872, 0.73889, 0.75619, 0.77058, 0.78200, 0.79037, 0.79562, 0.79770, 0.79662, 0.79238, 0.78505, 0.77463, 0.76119, 0.74477, 0.72543, 0.70323, 0.67824, 0.65061, 0.62046, 0.58787, 0.55293, 0.51582, 0.47673, 0.43580, 0.39314, 0.34891, 0.30334, 0.25659, 0.20882, 0.16024, 0.11106, 0.06146, 0.01160, -0.03830, -0.08801, -0.13736, -0.18618, -0.23428, -0.28147, -0.32756, -0.37239, -0.41576, -0.45752, -0.49750, -0.53555, -0.57148, -0.60517, -0.63654, -0.66545, -0.69174, -0.71533, -0.73615, -0.75411, -0.76911, -0.78108, -0.79000, -0.79583, -0.79849, -0.79799, -0.79436, -0.78766, -0.77792, -0.76515, -0.74939, -0.73069, -0.70911, -0.68473, -0.65765, -0.62797, -0.59582, -0.56134, -0.52467, -0.48594, -0.44529, -0.40288, -0.35886, -0.31341, -0.26671, -0.21892, -0.17027, -0.12095, -0.07118, -0.02110, 0.02908, 0.07913, 0.12885, 0.17807, 0.22659, 0.27422, 0.32078, 0.36610, 0.41003, 0.45236, 0.49295, 0.53165, 0.56828, 0.60270, 0.63479, 0.66442, 0.69145, 0.71576, 0.73727, 0.75592, 0.77161, 0.78424, 0.79381, 0.80029, 0.80362, 0.80376, 0.80075, 0.79461, 0.78533, 0.77293, 0.75749, 0.73909, 0.71773, 0.69351, 0.66657, 0.63701, 0.60492, 0.57044, 0.53374, 0.49490, 0.45404, 0.41137, 0.36712, 0.32143, 0.27442, 0.22640, 0.17775, 0.12871, 0.07942, 0.03003, -0.01923, -0.06821, -0.11679, -0.16482, -0.21214, -0.25863, -0.30421, -0.34876, -0.39211, -0.43416, -0.47488, -0.51414, -0.55183, -0.58788, -0.62226, -0.65487, -0.68559, -0.71439, -0.74126, -0.76612, -0.78888, -0.80949, -0.82795, -0.84420, -0.85817, -0.86982, -0.87913, -0.88607, -0.89062, -0.89276, -0.89248, -0.88975, -0.88456, -0.87692, -0.86685, -0.85432, -0.83934, -0.82193, -0.80214, -0.78002, -0.75561, -0.72896, -0.70016, -0.66925, -0.63629, -0.60139, -0.56467, -0.52620, -0.48608, -0.44443, -0.40142, -0.35720, -0.31183, -0.26544, -0.21822, -0.17036, -0.12204, -0.07337, -0.02448, 0.02448, 0.07337, 0.12204, 0.17036, 0.21822, 0.26544, 0.31183, 0.35720, 0.40142, 0.44443, 0.48608, 0.52620, 0.56467, 0.60139, 0.63629, 0.66925, 0.70016, 0.72896, 0.75561, 0.78002, 0.80214, 0.82193, 0.83934, 0.85432, 0.86685, 0.87692, 0.88456, 0.88975, 0.89248, 0.89276, 0.89062, 0.88607, 0.87913, 0.86982, 0.85817, 0.84420, 0.82795, 0.80949, 0.78888, 0.76612, 0.74126, 0.71439, 0.68559, 0.65487, 0.62226, 0.58788, 0.55183, 0.51414, 0.47488, 0.43416, 0.39211, 0.34876, 0.30421, 0.25863, 0.21214, 0.16482, 0.11679, 0.06821, 0.01923, -0.03003, -0.07942, -0.12871, -0.17775, -0.22640, -0.27442, -0.32143, -0.36712, -0.41137, -0.45404, -0.49490, -0.53374, -0.57044, -0.60492, -0.63701, -0.66657, -0.69351, -0.71773, -0.73909, -0.75749, -0.77293, -0.78533, -0.79461, -0.80075, -0.80376, -0.80362, -0.80029, -0.79381, -0.78424, -0.77161, -0.75592, -0.73727, -0.71576, -0.69145, -0.66442, -0.63479, -0.60270, -0.56828, -0.53165, -0.49295, -0.45236, -0.41003, -0.36610, -0.32078, -0.27422, -0.22659, -0.17807, -0.12885, -0.07913, -0.02908, 0.02110, 0.07118, 0.12095, 0.17027, 0.21892, 0.26671, 0.31341, 0.35886, 0.40288, 0.44529, 0.48594, 0.52467, 0.56134, 0.59582, 0.62797, 0.65765, 0.68473, 0.70911, 0.73069, 0.74939, 0.76515, 0.77792, 0.78766, 0.79436, 0.79799, 0.79849, 0.79583, 0.79000, 0.78108, 0.76911, 0.75411, 0.73615, 0.71533, 0.69174, 0.66545, 0.63654, 0.60517, 0.57148, 0.53555, 0.49750, 0.45752, 0.41576, 0.37239, 0.32756, 0.28147, 0.23428, 0.18618, 0.13736, 0.08801, 0.03830, -0.01160, -0.06146, -0.11106, -0.16024, -0.20882, -0.25659, -0.30334, -0.34891, -0.39314, -0.43580, -0.47673, -0.51582, -0.55293, -0.58787, -0.62046, -0.65061, -0.67824, -0.70323, -0.72543, -0.74477, -0.76119, -0.77463, -0.78505, -0.79238, -0.79662, -0.79770, -0.79562, -0.79037, -0.78200, -0.77058, -0.75619, -0.73889, -0.71872, -0.69575, -0.67006, -0.64174, -0.61091, -0.57769, -0.54222, -0.50457, -0.46488, -0.42336, -0.38019, -0.33551, -0.28943, -0.24218, -0.19401, -0.14508, -0.09552, -0.04555, 0.00459, 0.05472, 0.10469, 0.15431, 0.20336, 0.25161, 0.29891, 0.34508, 0.38990, 0.43321, 0.47484, 0.51464, 0.55245, 0.58808, 0.62140, 0.65230, 0.68065, 0.70631, 0.72918, 0.74919, 0.76627, 0.78031, 0.79124, 0.79907, 0.80376, 0.80526, 0.80358, 0.79878, 0.79086, 0.77976, 0.76555, 0.74839, 0.72830, 0.70523, 0.67937, 0.65106, 0.62029, 0.58678, 0.55083, 0.51362, 0.47617, 0.43840, 0.39967, 0.35988, 0.31956, 0.27906, 0.23835, 0.19747, 0.15668, 0.11623, 0.07619, 0.03663, -0.00221, -0.04012, -0.07703, -0.11283, -0.14736, -0.18049, -0.21211, -0.24215, -0.27052, -0.29714, -0.32197, -0.34494, -0.36597, -0.38504, -0.40211, -0.41715, -0.43016, -0.44112, -0.45002, -0.45689, -0.46175, -0.46464, -0.46555, -0.46456, -0.46171, -0.45704, -0.45058, -0.44243, -0.43269, -0.42139, -0.40859, -0.39443, -0.37904, -0.36246, -0.34475, -0.32606, -0.30652, -0.28620, -0.26512, -0.24344, -0.22131, -0.19880, -0.17592, -0.15278, -0.12956, -0.10640, -0.08332, -0.06037, -0.03764, -0.01522, 0.00678, 0.02828, 0.04915, 0.06931, 0.08867, 0.10722, 0.12498, 0.14189, 0.15782, 0.17271, 0.18655, 0.19934, 0.21101, 0.22152, 0.23088, 0.23908, 0.24610, 0.25195, 0.25666, 0.26023, 0.26263, 0.26389, 0.26408, 0.26319, 0.26122, 0.25819, 0.25419, 0.24927, 0.24342, 0.23671, 0.22922, 0.22098, 0.21201, 0.20237, 0.19213, 0.18136, 0.17010, 0.15842, 0.14638, 0.13403, 0.12143, 0.10864, 0.09573, 0.08274, 0.06972, 0.05675, 0.04387, 0.03113, 0.01856, 0.00621, -0.00587, -0.01763, -0.02900, -0.03998, -0.05056, -0.06069, -0.07030, -0.07935, -0.08786, -0.09586, -0.10334, -0.11028, -0.11665, -0.12241, -0.12753, -0.13201, -0.13590, -0.13919, -0.14184, -0.14380, -0.14512, -0.14585, -0.14601, -0.14557, -0.14456, -0.14300, -0.14092, -0.13831, -0.13521, -0.13165, -0.12768, -0.12329, -0.11850, -0.11335, -0.10790, -0.10215, -0.09613, -0.08986, -0.08341, -0.07678, -0.06997, -0.06301, -0.05595, -0.04878, -0.04154, -0.03427, -0.02705, -0.01986, -0.01270, -0.00564, 0.00126, 0.00799, 0.01456, 0.02093, 0.02705, 0.03292, 0.03852, 0.04380, 0.04875, 0.05342, 0.05777, 0.06174, 0.06532, 0.06857, 0.07150, 0.07403, 0.07616, 0.07797, 0.07948, 0.08063, 0.08141, 0.08187, 0.08203, 0.08185, 0.08134, 0.08055, 0.07947, 0.07803, 0.07628, 0.07432, 0.07217, 0.06980, 0.06721, 0.06445, 0.06151, 0.05837, 0.05506, 0.05160, 0.04798, 0.04420, 0.04032, 0.03641, 0.03246, 0.02847, 0.02445, 0.02046, 0.01650, 0.01258, 0.00870, 0.00491, 0.00120, -0.00242, -0.00593, -0.00933, -0.01262, -0.01580, -0.01883, -0.02172, -0.02447, -0.02709, -0.02955, -0.03185, -0.03400, -0.03599, -0.03782, -0.03945, -0.04090, -0.04220, -0.04332, -0.04427, -0.04503, -0.04560, -0.04598, -0.04619, -0.04624, -0.04612, -0.04582, -0.04535, -0.04472, -0.04392, -0.04296, -0.04183, -0.04058, -0.03921, -0.03774, -0.03617, -0.03452, -0.03282, -0.03102, -0.02908, -0.02702, -0.02487, -0.02267, -0.02041, -0.01811, -0.01581, -0.01351, -0.01121, -0.00892, -0.00669, -0.00454, -0.00245, -0.00037, 0.00166, 0.00363, 0.00553, 0.00739, 0.00920, 0.01093, 0.01258, 0.01417, 0.01567, 0.01707, 0.01838, 0.01960, 0.02070, 0.02166, 0.02251, 0.02328, 0.02395, 0.02446, 0.02486, 0.02516, 0.02535, 0.02539, 0.02529, 0.02509, 0.02481, 0.02442, 0.02395, 0.02339, 0.02273, 0.02195, 0.02110, 0.02017, 0.01915, 0.01802, 0.01687, 0.01573, 0.01459, 0.01339, 0.01217, 0.01094, 0.00967, 0.00836, 0.00707, 0.00583, 0.00458, 0.00331, 0.00204, 0.00083, -0.00035, -0.00154, -0.00268, -0.00376, -0.00481, -0.00585, -0.00686, -0.00779, -0.00867, -0.00948, -0.01019, -0.01082, -0.01139, -0.01190, -0.01230, -0.01262, -0.01291, -0.01316, -0.01332, -0.01340, -0.01342, -0.01341, -0.01334, -0.01322, -0.01307, -0.01287, -0.01262, -0.01235, -0.01207, -0.01177, -0.01144, -0.01111, -0.01076, -0.01039, -0.00998, -0.00955, -0.00911, -0.00862, -0.00810, -0.00756, -0.00701, -0.00641, -0.00578, -0.00515, -0.00455, -0.00395, -0.00339, -0.00285, -0.00231, -0.00174, -0.00117, -0.00063, -0.00009, 0.00050, 0.00113, 0.00172, 0.00224, 0.00270, 0.00313, 0.00352, 0.00390, 0.00423, 0.00447, 0.00462, 0.00471, 0.00478, 0.00488, 0.00500, 0.00510, 0.00517, 0.00522, 0.00528, 0.00533, 0.00532, 0.00525, 0.00518, 0.00509, 0.00495, 0.00478, 0.00459, 0.00441, 0.00422, 0.00402, 0.00382, 0.00361, 0.00338, 0.00315, 0.00293, 0.00270, 0.00243, 0.00214, 0.00183, 0.00150, 0.00113, 0.00073, 0.00033, -0.00008, -0.00048, -0.00087, -0.00126, -0.00164, -0.00199, -0.00232, -0.00263, -0.00293, -0.00320, -0.00342, -0.00361, -0.00379, -0.00396, -0.00409, -0.00421, -0.00433, -0.00443, -0.00451, -0.00457, -0.00461, -0.00462, -0.00464, -0.00468, -0.00469, -0.00466, -0.00460, -0.00451, -0.00439, -0.00419, -0.00397, -0.00376, -0.00355, -0.00332, -0.00309, -0.00287, -0.00263, -0.00236, -0.00208, -0.00183, -0.00156, -0.00128, -0.00099, -0.00067, -0.00032, 0.00007, 0.00048, 0.00090, 0.00136, 0.00182, 0.00225, 0.00266, 0.00305, 0.00343, 0.00376, 0.00405, 0.00432, 0.00459, 0.00483, 0.00504, 0.00521, 0.00536, 0.00547, 0.00554, 0.00559, 0.00564, 0.00571, 0.00576, 0.00577, 0.00576, 0.00577, 0.00577, 0.00574, 0.00571, 0.00570, 0.00566, 0.00554, 0.00543, 0.00532, 0.00511, 0.00476, 0.00445, 0.00426, 0.00402, 0.00359, 0.00312, 0.00283, 0.00259, 0.00217, 0.00165, 0.00131, 0.00112, 0.00084, 0.00042, 0.00002, -0.00027, -0.00057, -0.00096, -0.00137, -0.00174, -0.00213, -0.00258, -0.00304, -0.00349, -0.00392, -0.00435, -0.00476, -0.00515, -0.00550, -0.00581, -0.00610, -0.00637, -0.00659, -0.00675, -0.00688, -0.00700, -0.00708, -0.00711, -0.00712, -0.00714, -0.00713, -0.00707, -0.00701, -0.00696, -0.00689, -0.00680, -0.00669, -0.00658, -0.00644, -0.00627, -0.00607, -0.00582, -0.00550, -0.00515, -0.00476, -0.00431, -0.00379, -0.00327, -0.00275, -0.00219, -0.00157, -0.00098, -0.00045, 0.00010, 0.00072, 0.00135, 0.00188, 0.00233, 0.00275, 0.00318, 0.00365, 0.00416, 0.00463, 0.00497, 0.00524, 0.00556, 0.00592, 0.00624, 0.00650, 0.00676, 0.00703, 0.00722, 0.00733, 0.00740, 0.00747, 0.00751, 0.00750, 0.00745, 0.00738, 0.00728, 0.00716, 0.00704, 0.00689, 0.00673, 0.00656, 0.00637, 0.00614, 0.00588, 0.00560, 0.00528, 0.00489, 0.00447, 0.00403, 0.00358, 0.00307, 0.00254, 0.00201, 0.00150, 0.00097, 0.00042, -0.00012, -0.00063, -0.00111, -0.00156, -0.00199, -0.00239, -0.00277, -0.00311, -0.00347, -0.00382, -0.00412, -0.00435, -0.00457, -0.00481, -0.00506, -0.00529, -0.00552, -0.00576, -0.00598, -0.00617, -0.00639, -0.00663, -0.00683, -0.00695, -0.00700, -0.00701, -0.00698, -0.00691, -0.00682, -0.00673, -0.00660, -0.00641, -0.00622, -0.00605, -0.00587, -0.00565, -0.00538, -0.00512, -0.00487, -0.00459, -0.00430, -0.00399, -0.00368, -0.00336, -0.00304, -0.00272, -0.00242, -0.00212, -0.00181, -0.00151, -0.00123, -0.00098, -0.00072, -0.00047, -0.00024, -0.00003, 0.00018, 0.00039, 0.00059, 0.00080, 0.00101, 0.00123, 0.00144, 0.00167, 0.00194, 0.00223, 0.00252, 0.00283, 0.00317, 0.00351, 0.00382, 0.00412, 0.00443, 0.00471, 0.00494, 0.00519, 0.00549, 0.00582, 0.00611, 0.00635, 0.00655, 0.00673, 0.00690, 0.00706, 0.00715, 0.00714, 0.00707, 0.00699, 0.00688, 0.00673, 0.00654, 0.00634, 0.00612, 0.00586, 0.00558, 0.00532, 0.00506, 0.00476, 0.00443, 0.00409, 0.00374, 0.00336, 0.00295, 0.00252, 0.00205, 0.00154, 0.00102, 0.00050, -0.00003, -0.00056, -0.00106, -0.00151, -0.00193, -0.00235, -0.00274, -0.00309, -0.00340, -0.00369, -0.00395, -0.00418, -0.00440, -0.00459, -0.00473, -0.00483, -0.00490, -0.00494, -0.00495, -0.00493, -0.00490, -0.00484, -0.00475, -0.00466, -0.00456, -0.00443, -0.00427, -0.00413, -0.00401, -0.00386, -0.00364, -0.00338, -0.00313, -0.00291, -0.00268, -0.00241, -0.00211, -0.00183, -0.00157, -0.00131, -0.00100, -0.00065, -0.00033, -0.00008, 0.00012, 0.00029, 0.00041, 0.00047, 0.00051, 0.00053, 0.00053, 0.00050, 0.00046, 0.00038, 0.00025, 0.00010, -0.00005, -0.00020, -0.00035, -0.00050, -0.00061, -0.00070, -0.00080, -0.00089, -0.00095, -0.00099, -0.00104, -0.00109, -0.00109, -0.00104, -0.00099, -0.00095, -0.00089, -0.00080, -0.00070, -0.00061, -0.00050, -0.00035, -0.00020, -0.00005, 0.00010, 0.00025, 0.00038, 0.00046, 0.00050, 0.00053, 0.00053, 0.00051, 0.00047, 0.00041, 0.00029, 0.00012, -0.00008, -0.00033, -0.00065, -0.00100, -0.00131, -0.00157, -0.00183, -0.00211, -0.00241, -0.00268, -0.00291, -0.00313, -0.00338, -0.00364, -0.00386, -0.00401, -0.00413, -0.00427, -0.00443, -0.00456, -0.00466, -0.00475, -0.00484, -0.00490, -0.00493, -0.00495, -0.00494, -0.00490, -0.00483, -0.00473, -0.00459, -0.00440, -0.00418, -0.00395, -0.00369, -0.00340, -0.00309, -0.00274, -0.00235, -0.00193, -0.00151, -0.00106, -0.00056, -0.00003, 0.00050, 0.00102, 0.00154, 0.00205, 0.00252, 0.00295, 0.00336, 0.00374, 0.00409, 0.00443, 0.00476, 0.00506, 0.00532, 0.00558, 0.00586, 0.00612, 0.00634, 0.00654, 0.00673, 0.00688, 0.00699, 0.00707, 0.00714, 0.00715, 0.00706, 0.00690, 0.00673, 0.00655, 0.00635, 0.00611, 0.00582, 0.00549, 0.00519, 0.00494, 0.00471, 0.00443, 0.00412, 0.00382, 0.00351, 0.00317, 0.00283, 0.00252, 0.00223, 0.00194, 0.00167, 0.00144, 0.00123, 0.00101, 0.00080, 0.00059, 0.00039, 0.00018, -0.00003, -0.00024, -0.00047, -0.00072, -0.00098, -0.00123, -0.00151, -0.00181, -0.00212, -0.00242, -0.00272, -0.00304, -0.00336, -0.00368, -0.00399, -0.00430, -0.00459, -0.00487, -0.00512, -0.00538, -0.00565, -0.00587, -0.00605, -0.00622, -0.00641, -0.00660, -0.00673, -0.00682, -0.00691, -0.00698, -0.00701, -0.00700, -0.00695, -0.00683, -0.00663, -0.00639, -0.00617, -0.00598, -0.00576, -0.00552, -0.00529, -0.00506, -0.00481, -0.00457, -0.00435, -0.00412, -0.00382, -0.00347, -0.00311, -0.00277, -0.00239, -0.00199, -0.00156, -0.00111, -0.00063, -0.00012, 0.00042, 0.00097, 0.00150, 0.00201, 0.00254, 0.00307, 0.00358, 0.00403, 0.00447, 0.00489, 0.00528, 0.00560, 0.00588, 0.00614, 0.00637, 0.00656, 0.00673, 0.00689, 0.00704, 0.00716, 0.00728, 0.00738, 0.00745, 0.00750, 0.00751, 0.00747, 0.00740, 0.00733, 0.00722, 0.00703, 0.00676, 0.00650, 0.00624, 0.00592, 0.00556, 0.00524, 0.00497, 0.00463, 0.00416, 0.00365, 0.00318, 0.00275, 0.00233, 0.00188, 0.00135, 0.00072, 0.00010, -0.00045, -0.00098, -0.00157, -0.00219, -0.00275, -0.00327, -0.00379, -0.00431, -0.00476, -0.00515, -0.00550, -0.00582, -0.00607, -0.00627, -0.00644, -0.00658, -0.00669, -0.00680, -0.00689, -0.00696, -0.00701, -0.00707, -0.00713, -0.00714, -0.00712, -0.00711, -0.00708, -0.00700, -0.00688, -0.00675, -0.00659, -0.00637, -0.00610, -0.00581, -0.00550, -0.00515, -0.00476, -0.00435, -0.00392, -0.00349, -0.00304, -0.00258, -0.00213, -0.00174, -0.00137, -0.00096, -0.00057, -0.00027, 0.00002, 0.00042, 0.00084, 0.00112, 0.00131, 0.00165, 0.00217, 0.00259, 0.00283, 0.00312, 0.00359, 0.00402, 0.00426, 0.00445, 0.00476, 0.00511, 0.00532, 0.00543, 0.00554, 0.00566, 0.00570, 0.00571, 0.00574, 0.00577, 0.00577, 0.00576, 0.00577, 0.00576, 0.00571, 0.00564, 0.00559, 0.00554, 0.00547, 0.00536, 0.00521, 0.00504, 0.00483, 0.00459, 0.00432, 0.00405, 0.00376, 0.00343, 0.00305, 0.00266, 0.00225, 0.00182, 0.00136, 0.00090, 0.00048, 0.00007, -0.00032, -0.00067, -0.00099, -0.00128, -0.00156, -0.00183, -0.00208, -0.00236, -0.00263, -0.00287, -0.00309, -0.00332, -0.00355, -0.00376, -0.00397, -0.00419, -0.00439, -0.00451, -0.00460, -0.00466, -0.00469, -0.00468, -0.00464, -0.00462, -0.00461, -0.00457, -0.00451, -0.00443, -0.00433, -0.00421, -0.00409, -0.00396, -0.00379, -0.00361, -0.00342, -0.00320, -0.00293, -0.00263, -0.00232, -0.00199, -0.00164, -0.00126, -0.00087, -0.00048, -0.00008, 0.00033, 0.00073, 0.00113, 0.00150, 0.00183, 0.00214, 0.00243, 0.00270, 0.00293, 0.00315, 0.00338, 0.00361, 0.00382, 0.00402, 0.00422, 0.00441, 0.00459, 0.00478, 0.00495, 0.00509, 0.00518, 0.00525, 0.00532, 0.00533, 0.00528, 0.00522, 0.00517, 0.00510, 0.00500, 0.00488, 0.00478, 0.00471, 0.00462, 0.00447, 0.00423, 0.00390, 0.00352, 0.00313, 0.00270, 0.00224, 0.00172, 0.00113, 0.00050, -0.00009, -0.00063, -0.00117, -0.00174, -0.00231, -0.00285, -0.00339, -0.00395, -0.00455, -0.00515, -0.00578, -0.00641, -0.00701, -0.00756, -0.00810, -0.00862, -0.00911, -0.00955, -0.00998, -0.01039, -0.01076, -0.01111, -0.01144, -0.01177, -0.01207, -0.01235, -0.01262, -0.01287, -0.01307, -0.01322, -0.01334, -0.01341, -0.01342, -0.01340, -0.01332, -0.01316, -0.01291, -0.01262, -0.01230, -0.01190, -0.01139, -0.01082, -0.01019, -0.00948, -0.00867, -0.00779, -0.00686, -0.00585, -0.00481, -0.00376, -0.00268, -0.00154, -0.00035, 0.00083, 0.00204, 0.00331, 0.00458, 0.00583, 0.00707, 0.00836, 0.00967, 0.01094, 0.01217, 0.01339, 0.01459, 0.01573, 0.01687, 0.01802, 0.01915, 0.02017, 0.02110, 0.02195, 0.02273, 0.02339, 0.02395, 0.02442, 0.02481, 0.02509, 0.02529, 0.02539, 0.02535, 0.02516, 0.02486, 0.02446, 0.02395, 0.02328, 0.02251, 0.02166, 0.02070, 0.01960, 0.01838, 0.01707, 0.01567, 0.01417, 0.01258, 0.01093, 0.00920, 0.00739, 0.00553, 0.00363, 0.00166, -0.00037, -0.00245]; pub fn imdct_prepare(arr :&[f32]) -> Vec { let mut res = Vec::with_capacity(arr.len() * 2); res.extend_from_slice(arr); for _ in 0 .. arr.len() { res.push(0.); } return res; } pub fn fuzzy_compare_array(arr_a :&[f32], arr_b :&[f32], epsilon :f32, print_mismatches :bool) -> usize { let mut mismatch_cnt :usize = 0; for ((idx, entry_a), entry_b) in arr_a.iter().enumerate().zip(arr_b) { if (entry_a - entry_b).abs() >= epsilon { if print_mismatches { println!("Mismatch at idx {}. Expected {} but was {}", idx, entry_a, entry_b); } mismatch_cnt += 1; } } return mismatch_cnt; } lewton-0.10.2/src/inside_ogg.rs010066400017500001750000000306661373056705700145610ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Higher-level utilities for Ogg streams and files This module provides higher level access to the library functionality, and useful helper methods for the Ogg `PacketReader` struct. */ use ogg::{PacketReader, Packet}; use header::*; use VorbisError; use std::io::{Read, Seek}; use ::audio::{PreviousWindowRight, read_audio_packet, read_audio_packet_generic}; use ::header::HeaderSet; use ::samples::{Samples, InterleavedSamples}; /// Reads the three vorbis headers from an ogg stream as well as stream serial information /// /// Please note that this function doesn't work well with async /// I/O. In order to support this use case, enable the `async_ogg` feature, /// and use the `HeadersReader` struct instead. pub fn read_headers<'a, T: Read + Seek + 'a>(rdr: &mut PacketReader) -> Result<(HeaderSet, u32), VorbisError> { let pck :Packet = try!(rdr.read_packet_expected()); let ident_hdr = try!(read_header_ident(&pck.data)); let stream_serial = pck.stream_serial(); let mut pck :Packet = try!(rdr.read_packet_expected()); while pck.stream_serial() != stream_serial { pck = try!(rdr.read_packet_expected()); } let comment_hdr = try!(read_header_comment(&pck.data)); let mut pck :Packet = try!(rdr.read_packet_expected()); while pck.stream_serial() != stream_serial { pck = try!(rdr.read_packet_expected()); } let setup_hdr = try!(read_header_setup(&pck.data, ident_hdr.audio_channels, (ident_hdr.blocksize_0, ident_hdr.blocksize_1))); rdr.delete_unread_packets(); return Ok(((ident_hdr, comment_hdr, setup_hdr), pck.stream_serial())); } /** Reading ogg/vorbis files or streams This is a small helper struct to help reading ogg/vorbis files or streams in that format. It only supports the main use case of pure audio ogg files streams. Reading a file where vorbis is only one of multiple streams, like in the case of ogv, is not supported. If you need support for this, you need to use the lower level methods instead. */ pub struct OggStreamReader { rdr :PacketReader, pwr :PreviousWindowRight, stream_serial :u32, pub ident_hdr :IdentHeader, pub comment_hdr :CommentHeader, pub setup_hdr :SetupHeader, cur_absgp :Option, } impl OggStreamReader { /// Constructs a new OggStreamReader from a given implementation of `Read + Seek`. /// /// Please note that this function doesn't work well with async /// I/O. In order to support this use case, enable the `async_ogg` feature, /// and use the `HeadersReader` struct instead. pub fn new(rdr :T) -> Result { OggStreamReader::from_ogg_reader(PacketReader::new(rdr)) } /// Constructs a new OggStreamReader from a given Ogg PacketReader. /// /// The `new` function is a nice wrapper around this function that /// also creates the ogg reader. /// /// Please note that this function doesn't work well with async /// I/O. In order to support this use case, enable the `async_ogg` feature, /// and use the `HeadersReader` struct instead. pub fn from_ogg_reader(mut rdr :PacketReader) -> Result { let ((ident_hdr, comment_hdr, setup_hdr), stream_serial) = try!(read_headers(&mut rdr)); return Ok(OggStreamReader { rdr, pwr : PreviousWindowRight::new(), ident_hdr, comment_hdr, setup_hdr, stream_serial, cur_absgp : None, }); } pub fn into_inner(self) -> PacketReader { self.rdr } fn read_next_audio_packet(&mut self) -> Result, VorbisError> { loop { let pck = match try!(self.rdr.read_packet()) { Some(p) => p, None => return Ok(None), }; if pck.stream_serial() != self.stream_serial { if pck.first_in_stream() { // We have a chained ogg file. This means we need to // re-initialize the internal context. let ident_hdr = try!(read_header_ident(&pck.data)); let pck :Packet = try!(self.rdr.read_packet_expected()); let comment_hdr = try!(read_header_comment(&pck.data)); let pck :Packet = try!(self.rdr.read_packet_expected()); let setup_hdr = try!(read_header_setup(&pck.data, ident_hdr.audio_channels, (ident_hdr.blocksize_0, ident_hdr.blocksize_1))); // Update the context self.pwr = PreviousWindowRight::new(); self.ident_hdr = ident_hdr; self.comment_hdr = comment_hdr; self.setup_hdr = setup_hdr; self.stream_serial = pck.stream_serial(); self.cur_absgp = None; // Now, read the first audio packet to prime the pwr // and discard the packet. let pck = match try!(self.rdr.read_packet()) { Some(p) => p, None => return Ok(None), }; let _decoded_pck = try!(read_audio_packet(&self.ident_hdr, &self.setup_hdr, &pck.data, &mut self.pwr)); self.cur_absgp = Some(pck.absgp_page()); return Ok(try!(self.rdr.read_packet())); } else { // Ignore every packet that has a mismatching stream serial } } else { return Ok(Some(pck)); } } } /// Reads and decompresses an audio packet from the stream. /// /// On read errors, it returns Err(e) with the error. /// /// On success, it either returns None, when the end of the /// stream has been reached, or Some(packet_data), /// with the data of the decompressed packet. pub fn read_dec_packet(&mut self) -> Result>>, VorbisError> { let pck = try!(self.read_dec_packet_generic()); Ok(pck) } /// Reads and decompresses an audio packet from the stream (generic). /// /// On read errors, it returns Err(e) with the error. /// /// On success, it either returns None, when the end of the /// stream has been reached, or Some(packet_data), /// with the data of the decompressed packet. pub fn read_dec_packet_generic(&mut self) -> Result, VorbisError> { let pck = match try!(self.read_next_audio_packet()) { Some(p) => p, None => return Ok(None), }; let mut decoded_pck :S = try!(read_audio_packet_generic(&self.ident_hdr, &self.setup_hdr, &pck.data, &mut self.pwr)); // If this is the last packet in the logical bitstream, // we need to truncate it so that its ending matches // the absgp of the current page. // This is what the spec mandates and also the behaviour // of libvorbis. if let (Some(absgp), true) = (self.cur_absgp, pck.last_in_stream()) { let target_length = pck.absgp_page().saturating_sub(absgp) as usize; decoded_pck.truncate(target_length); } if pck.last_in_page() { self.cur_absgp = Some(pck.absgp_page()); } else if let &mut Some(ref mut absgp) = &mut self.cur_absgp { *absgp += decoded_pck.num_samples() as u64; } return Ok(Some(decoded_pck)); } /// Reads and decompresses an audio packet from the stream (interleaved). /// /// On read errors, it returns Err(e) with the error. /// /// On success, it either returns None, when the end of the /// stream has been reached, or Some(packet_data), /// with the data of the decompressed packet. /// /// Unlike `read_dec_packet`, this function returns the /// interleaved samples. pub fn read_dec_packet_itl(&mut self) -> Result>, VorbisError> { let decoded_pck :InterleavedSamples<_> = match try!(self.read_dec_packet_generic()) { Some(p) => p, None => return Ok(None), }; return Ok(Some(decoded_pck.samples)); } /// Returns the stream serial of the current stream /// /// The stream serial can change in chained ogg files. pub fn stream_serial(&self) -> u32 { self.stream_serial } /// Returns the absolute granule position of the last read page. /// /// In the case of ogg/vorbis, the absolute granule position is given /// as number of PCM samples, on a per channel basis. pub fn get_last_absgp(&self) -> Option { self.cur_absgp } /// Seeks to the specified absolute granule position, with a page granularity. /// /// The granularity is per-page, and the obtained position is /// then <= the seeked absgp. /// /// In the case of ogg/vorbis, the absolute granule position is given /// as number of PCM samples, on a per channel basis. pub fn seek_absgp_pg(&mut self, absgp :u64) -> Result<(), VorbisError> { try!(self.rdr.seek_absgp(None, absgp)); // Reset the internal state after the seek self.cur_absgp = None; self.pwr = PreviousWindowRight::new(); Ok(()) } } #[cfg(feature = "async_ogg")] /** Support for async I/O This module provides support for asyncronous I/O. */ pub mod async_api { use super::*; use ogg::OggReadError; use ogg::reading::async_api::PacketReader; use futures::stream::Stream; use tokio_io::AsyncRead; use futures::{Async, Future, Poll}; use std::io::{Error, ErrorKind}; use std::mem::replace; /// Async ready creator utility to read headers out of an /// ogg stream. /// /// All functions this struct has are ready to be used for operation with async I/O. pub struct HeadersReader { pck_rd :PacketReader, ident_hdr :Option, comment_hdr :Option, } impl HeadersReader { pub fn new(inner :T) -> Self { HeadersReader::from_packet_reader(PacketReader::new(inner)) } pub fn from_packet_reader(pck_rd :PacketReader) -> Self { HeadersReader { pck_rd, ident_hdr : None, comment_hdr : None, } } } impl Future for HeadersReader { type Item = HeaderSet; type Error = VorbisError; fn poll(&mut self) -> Poll { macro_rules! rd_pck { () => { if let Some(pck) = try_ready!(self.pck_rd.poll()) { pck } else { // Note: we are stealing the Io variant from // the ogg crate here which is not 100% clean, // but I think in general it is what the // read_packet_expected function of the ogg // crate does too, and adding our own case // to the VorbisError enum that only fires // in an async mode is too complicated IMO. try!(Err(OggReadError::ReadError(Error::new(ErrorKind::UnexpectedEof, "Expected header packet but found end of stream")))) } } } if self.ident_hdr.is_none() { let pck = rd_pck!(); self.ident_hdr = Some(try!(read_header_ident(&pck.data))); } if self.comment_hdr.is_none() { let pck = rd_pck!(); self.comment_hdr = Some(try!(read_header_comment(&pck.data))); } let setup_hdr = { let ident = self.ident_hdr.as_ref().unwrap(); let pck = rd_pck!(); try!(read_header_setup(&pck.data, ident.audio_channels, (ident.blocksize_0, ident.blocksize_1))) }; let ident_hdr = replace(&mut self.ident_hdr, None).unwrap(); let comment_hdr = replace(&mut self.comment_hdr, None).unwrap(); Ok(Async::Ready((ident_hdr, comment_hdr, setup_hdr))) } } /// Reading ogg/vorbis files or streams /// /// This is a small helper struct to help reading ogg/vorbis files /// or streams in that format. /// /// It only supports the main use case of pure audio ogg files streams. /// Reading a file where vorbis is only one of multiple streams, like /// in the case of ogv, is not supported. /// /// If you need support for this, you need to use the lower level methods /// instead. pub struct OggStreamReader { pck_rd :PacketReader, pwr :PreviousWindowRight, pub ident_hdr :IdentHeader, pub comment_hdr :CommentHeader, pub setup_hdr :SetupHeader, absgp_of_last_read :Option, } impl OggStreamReader { /// Creates a new OggStreamReader from the given parameters pub fn new(hdr_rdr :HeadersReader, hdrs :HeaderSet) -> Self { OggStreamReader::from_pck_rdr(hdr_rdr.pck_rd, hdrs) } /// Creates a new OggStreamReader from the given parameters pub fn from_pck_rdr(pck_rd :PacketReader, hdrs :HeaderSet) -> Self { OggStreamReader { pck_rd, pwr : PreviousWindowRight::new(), ident_hdr : hdrs.0, comment_hdr : hdrs.1, setup_hdr : hdrs.2, absgp_of_last_read : None, } } } impl Stream for OggStreamReader { type Item = Vec>; type Error = VorbisError; fn poll(&mut self) -> Poll>>, VorbisError> { let pck = match try_ready!(self.pck_rd.poll()) { Some(p) => p, None => return Ok(Async::Ready(None)), }; let decoded_pck = try!(read_audio_packet(&self.ident_hdr, &self.setup_hdr, &pck.data, &mut self.pwr)); self.absgp_of_last_read = Some(pck.absgp_page()); Ok(Async::Ready(Some(decoded_pck))) } } } lewton-0.10.2/src/lib.rs010066400017500001750000000144161400207637700132040ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2016 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. #![cfg_attr(not(cargo_c), forbid(unsafe_code))] #![cfg_attr(test, deny(warnings))] /*! A `vorbis` decoder, written in Rust. If you "just" want to decode `ogg/vorbis` files, take a look into the `inside_ogg` module (make sure you haven't disabled the `ogg` feature). For lower level, per-packet usage, you can have a look at the `audio` and `header` modules. */ extern crate byteorder; extern crate tinyvec; #[cfg(feature = "ogg")] extern crate ogg; #[cfg(feature = "async_ogg")] #[macro_use] extern crate futures; #[cfg(feature = "async_ogg")] extern crate tokio_io; macro_rules! try { ($expr:expr) => (match $expr { $crate::std::result::Result::Ok(val) => val, $crate::std::result::Result::Err(err) => { return Err($crate::std::convert::From::from(err)); } }) } /* // This little thing is very useful. macro_rules! try { ($expr:expr) => (match $expr { $crate::std::result::Result::Ok(val) => val, $crate::std::result::Result::Err(err) => { panic!("Panic on Err turned on for debug reasons. Encountered Err: {:?}", err) } }) } // */ // The following macros are super useful for debugging macro_rules! record_residue_pre_inverse { ($residue_vectors:expr) => { // for v in $residue_vectors.iter() { // for &re in v { // println!("{}", re); // } // } } } macro_rules! record_residue_post_inverse { ($residue_vectors:expr) => { // for v in $residue_vectors.iter() { // for &re in v { // println!("{}", re); // } // } } } macro_rules! record_pre_mdct { ($audio_spectri:expr) => { // for v in $audio_spectri.iter() { // for &s in v { // println!("{:.5}", s); // } // } } } macro_rules! record_post_mdct { ($audio_spectri:expr) => { // for v in $audio_spectri.iter() { // for &s in v { // println!("{:.4}", s); // } // } } } pub mod header; mod header_cached; mod huffman_tree; mod imdct; #[cfg(test)] mod imdct_test; pub mod audio; mod bitpacking; #[cfg(feature = "ogg")] pub mod inside_ogg; pub mod samples; #[cfg(feature = "ogg")] #[doc(no_inline)] pub use ogg::OggReadError; #[cfg(cargo_c)] mod capi; #[cfg(cargo_c)] pub use capi::*; /// Errors that can occur during decoding #[derive(Debug)] pub enum VorbisError { BadAudio(audio::AudioReadError), BadHeader(header::HeaderReadError), #[cfg(feature = "ogg")] OggError(OggReadError), } impl std::error::Error for VorbisError {} impl std::fmt::Display for VorbisError { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(fmt, "{}", match self { VorbisError::BadAudio(_) => "Vorbis bitstream audio decode problem", VorbisError::BadHeader(_) => "Vorbis bitstream header decode problem", #[cfg(feature = "ogg")] VorbisError::OggError(_) => "Ogg decode problem", }) } } impl From for VorbisError { fn from(err :audio::AudioReadError) -> VorbisError { VorbisError::BadAudio(err) } } impl From for VorbisError { fn from(err :header::HeaderReadError) -> VorbisError { VorbisError::BadHeader(err) } } #[cfg(feature = "ogg")] impl From for VorbisError { fn from(err :OggReadError) -> VorbisError { VorbisError::OggError(err) } } fn ilog(val :u64) -> u8 { 64 - val.leading_zeros() as u8 } #[test] fn test_ilog() { // Uses the test vectors from the Vorbis I spec assert_eq!(ilog(0), 0); assert_eq!(ilog(1), 1); assert_eq!(ilog(2), 2); assert_eq!(ilog(3), 2); assert_eq!(ilog(4), 3); assert_eq!(ilog(7), 3); } fn bit_reverse(n :u32) -> u32 { // From the stb_vorbis implementation let mut nn = n; nn = ((nn & 0xAAAAAAAA) >> 1) | ((nn & 0x55555555) << 1); nn = ((nn & 0xCCCCCCCC) >> 2) | ((nn & 0x33333333) << 2); nn = ((nn & 0xF0F0F0F0) >> 4) | ((nn & 0x0F0F0F0F) << 4); nn = ((nn & 0xFF00FF00) >> 8) | ((nn & 0x00FF00FF) << 8); return (nn >> 16) | (nn << 16); } #[allow(dead_code)] fn print_u8_slice(arr :&[u8]) { if arr.len() <= 4 { for a in arr { print!("0x{:02x} ", a); } println!(""); return; } println!("["); let mut i :usize = 0; while i * 4 < arr.len() - 4 { println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x},", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]); i += 1; } match arr.len() as i64 - i as i64 * 4 { 1 => println!("\t0x{:02x}];", arr[i * 4]), 2 => println!("\t0x{:02x}, 0x{:02x}];", arr[i * 4], arr[i * 4 + 1]), 3 => println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]), 4 => println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]), de => panic!("impossible value {}", de), } } #[allow(dead_code)] fn print_u32_slice(arr :&[u32]) { if arr.len() <= 4 { for a in arr { print!("0x{:02x} ", a); } println!(""); return; } println!("["); let mut i :usize = 0; while i * 4 < arr.len() - 4 { println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x},", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]); i += 1; } match arr.len() as i64 - i as i64 * 4 { 1 => println!("\t0x{:08x}];", arr[i * 4]), 2 => println!("\t0x{:08x}, 0x{:08x}];", arr[i * 4], arr[i * 4 + 1]), 3 => println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]), 4 => println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]), de => panic!("impossible value {}", de), } } #[allow(dead_code)] fn print_f64_slice(arr :&[f64]) { if arr.len() <= 4 { for a in arr { print!("0x{} ", a); } println!(""); return; } println!("["); let mut i :usize = 0; while i * 4 < arr.len() - 4 { println!("\t{}, {}, {}, {},", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]); i += 1; } match arr.len() as i64 - i as i64 * 4 { 1 => println!("\t{}];", arr[i * 4]), 2 => println!("\t{}, {}];", arr[i * 4], arr[i * 4 + 1]), 3 => println!("\t{}, {}, {}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]), 4 => println!("\t{}, {}, {}, {}];", arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]), de => panic!("impossible value {}", de), } } lewton-0.10.2/src/samples.rs010066400017500001750000000044361367240530400141010ustar 00000000000000// Vorbis decoder written in Rust // // Copyright (c) 2019 est31 // and contributors. All rights reserved. // Licensed under MIT license, or Apache 2 license, // at your option. Please see the LICENSE file // attached to this source distribution for details. /*! Traits for sample formats */ /// Trait for a packet of multiple samples pub trait Samples { fn num_samples(&self) -> usize; fn truncate(&mut self, limit :usize); fn from_floats(floats :Vec>) -> Self; } impl Samples for Vec> { fn num_samples(&self) -> usize { self[0].len() } fn truncate(&mut self, limit :usize) { for ch in self.iter_mut() { if limit < ch.len() { ch.truncate(limit); } } } fn from_floats(floats :Vec>) -> Self { floats.into_iter() .map(|samples| { samples.into_iter() .map(S::from_float) .collect() }).collect() } } /// A packet of multi-channel interleaved samples pub struct InterleavedSamples { pub samples :Vec, pub channel_count :usize, } impl Samples for InterleavedSamples { fn num_samples(&self) -> usize { self.samples.len() / self.channel_count } fn truncate(&mut self, limit :usize) { self.samples.truncate(limit * self.channel_count); } fn from_floats(floats :Vec>) -> Self { let channel_count = floats.len(); // Note that a channel count of 0 is forbidden // by the spec and the header decoding code already // checks for that. assert!(floats.len() > 0); let samples_interleaved = if channel_count == 1 { // Because decoded_pck[0] doesn't work... > as Samples>::from_floats(floats).into_iter().next().unwrap() } else { let len = floats[0].len(); let mut samples = Vec::with_capacity(len * channel_count); for i in 0 .. len { for ref chan in floats.iter() { samples.push(S::from_float(chan[i])); } } samples }; Self { samples : samples_interleaved, channel_count, } } } /// Trait representing a single sample pub trait Sample { fn from_float(fl :f32) -> Self; } impl Sample for f32 { fn from_float(fl :f32) -> Self { fl } } impl Sample for i16 { fn from_float(fl :f32) -> Self { let fl = fl * 32768.0; if fl > 32767. { 32767 } else if fl < -32768. { -32768 } else { fl as i16 } } }