Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/lewton/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"CHANGELOG.md":"888906b00223bbfe03857d6bcf8838ee97fa1fa7c5720534db3770ae7230d3fc","Cargo.lock":"df3666f5af938884db43b97cab8c73a98c398163b88a373d6e53506af351509f","Cargo.toml":"40af03fae56c325ff29982a29267df418599abc405bc3a5f0f1f715e94a3cceb","LICENSE":"9e32628a9d574751cb0a0136a207221b55ca3d95bde271880343a73de20b5964","README.md":"9302b01ef6e0b3d4996a6217f52fcfd375f696594843e454ef31732745b52b20","cbindgen.toml":"d8174eb8beeb7e3c2093079e3ed2b5018d180d878b7a2ae861f37e1f8b500611","examples/perf.rs":"cd3c2b0d9285cc33d92cb1bbd4ffd2aaca48864d614e5f53ba21eb8b7f7518e8","examples/player.rs":"4d6334d5cb73d055016ce436aa13cabed4e1c22980c3b8ea4f791fcdea0b5d94","src/audio.rs":"32a01fc396fc6964a3b81d519e84ab0092dcb075a80c4714379b122c7e070fd9","src/bitpacking.rs":"1b67e15028d395864877517e339b993b991f3b658dd48dd358ea1cbfbe5d3981","src/capi.rs":"e8a26f5a391ec6c5d80919056f07d94f9f701383b66abc0fff2e0973b2765dec","src/header.rs":"8629dd0f546161e8c874b16cd2edb3243d74afc33fa37c143a4c49ce8e0ea1ff","src/header_cached.rs":"5498bc67f6fcd098ca1ebcdfb3df0f45a683807d68fc19401dd80058bf3bb720","src/huffman_tree.rs":"c0fece28fb3bfee64f7d535df168a77b8af5f1aeeb797453d49a08de8616cce7","src/imdct.rs":"631aac8320e163858532c6ecfaaf1c6bf0e228b3e99ca3e6b503e3291a3491c6","src/imdct_test.rs":"a709a6f7d41a518a9e8ee699ed49ce6ecd60f6f8692d01371d53d7204d0869e1","src/inside_ogg.rs":"2870212680c68160d4010b16d75c7845ece351d207c18a1a815f283a582d2bf1","src/lib.rs":"727f9f07d1035eacf9b57ca6e0d805ec84a29b77319702bc54e065447f9323cf","src/samples.rs":"af927996653546f940e6f0f6f4450bcd229d49d9f323c143ec2be7355a02f680"},"package":"777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"}

139
vendor/lewton/CHANGELOG.md vendored Normal file
View File

@@ -0,0 +1,139 @@
# 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.

331
vendor/lewton/Cargo.lock generated vendored Normal file
View File

@@ -0,0 +1,331 @@
# 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"

64
vendor/lewton/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,64 @@
# 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 <MTest31@outlook.com>"]
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"]

214
vendor/lewton/LICENSE vendored Normal file
View File

@@ -0,0 +1,214 @@
Copyright (c) 2016 est31 <MTest31@outlook.com> 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 <MTest31@outlook.com> 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

83
vendor/lewton/README.md vendored Normal file
View File

@@ -0,0 +1,83 @@
# 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.

7
vendor/lewton/cbindgen.toml vendored Normal file
View File

@@ -0,0 +1,7 @@
header = "// 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"

47
vendor/lewton/examples/perf.rs vendored Normal file
View File

@@ -0,0 +1,47 @@
// 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(())
}

89
vendor/lewton/examples/player.rs vendored Normal file
View File

@@ -0,0 +1,89 @@
// 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::<Mono<i16>,_>(&pck_samples, sample_rate),
2 => cxt.new_buffer::<Stereo<i16>,_>(&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(())
}

1175
vendor/lewton/src/audio.rs vendored Normal file

File diff suppressed because it is too large Load Diff

589
vendor/lewton/src/bitpacking.rs vendored Normal file
View File

@@ -0,0 +1,589 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<bool, ()> {
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<f32, ()> {
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<u8, ()> {
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<u32, ()> {
//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);
}

147
vendor/lewton/src/capi.rs vendored Normal file
View File

@@ -0,0 +1,147 @@
use 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<u64> {
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<Self> {
// 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<Vec<f32>>);
/// 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));
}

1152
vendor/lewton/src/header.rs vendored Normal file

File diff suppressed because it is too large Load Diff

156
vendor/lewton/src/header_cached.rs vendored Normal file
View File

@@ -0,0 +1,156 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<f32>,
pub b :Vec<f32>,
pub c :Vec<f32>,
}
pub struct CachedBlocksizeDerived {
pub twiddle_factors : TwiddleFactors,
pub window_slope : Vec<f32>,
pub bitrev : Vec<u32>,
}
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<f32> {
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<u32> {
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<f32> {
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;
}

485
vendor/lewton/src/huffman_tree.rs vendored Normal file
View File

@@ -0,0 +1,485 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<u32>,
l :Option<Box<HuffTree>>,
r :Option<Box<HuffTree>>,
}
/*
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<u32>,
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<VorbisHuffmanTree, HuffmanError> {
// 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>) -> 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<u32>,
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<u32> {
// 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();
}

847
vendor/lewton/src/imdct.rs vendored Normal file
View File

@@ -0,0 +1,847 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<f32> = 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);
}
}

1005
vendor/lewton/src/imdct_test.rs vendored Normal file

File diff suppressed because it is too large Load Diff

390
vendor/lewton/src/inside_ogg.rs vendored Normal file
View File

@@ -0,0 +1,390 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<T>) ->
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<T: Read + Seek> {
rdr :PacketReader<T>,
pwr :PreviousWindowRight,
stream_serial :u32,
pub ident_hdr :IdentHeader,
pub comment_hdr :CommentHeader,
pub setup_hdr :SetupHeader,
cur_absgp :Option<u64>,
}
impl<T: Read + Seek> OggStreamReader<T> {
/// 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<Self, VorbisError> {
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<T>) ->
Result<Self, VorbisError> {
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<T> {
self.rdr
}
fn read_next_audio_packet(&mut self) -> Result<Option<Packet>, 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<Option<Vec<Vec<i16>>>, 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<S :Samples>(&mut self) ->
Result<Option<S>, 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<Option<Vec<i16>>, 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<u64> {
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<T: AsyncRead> {
pck_rd :PacketReader<T>,
ident_hdr :Option<IdentHeader>,
comment_hdr :Option<CommentHeader>,
}
impl<T: AsyncRead> HeadersReader<T> {
pub fn new(inner :T) -> Self {
HeadersReader::from_packet_reader(PacketReader::new(inner))
}
pub fn from_packet_reader(pck_rd :PacketReader<T>) -> Self {
HeadersReader {
pck_rd,
ident_hdr : None,
comment_hdr : None,
}
}
}
impl<T: AsyncRead> Future for HeadersReader<T> {
type Item = HeaderSet;
type Error = VorbisError;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
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<T :AsyncRead> {
pck_rd :PacketReader<T>,
pwr :PreviousWindowRight,
pub ident_hdr :IdentHeader,
pub comment_hdr :CommentHeader,
pub setup_hdr :SetupHeader,
absgp_of_last_read :Option<u64>,
}
impl<T :AsyncRead> OggStreamReader<T> {
/// Creates a new OggStreamReader from the given parameters
pub fn new(hdr_rdr :HeadersReader<T>, 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<T>, 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<T :AsyncRead> Stream for OggStreamReader<T> {
type Item = Vec<Vec<i16>>;
type Error = VorbisError;
fn poll(&mut self) -> Poll<Option<Vec<Vec<i16>>>, 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)))
}
}
}

264
vendor/lewton/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,264 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// 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<audio::AudioReadError> for VorbisError {
fn from(err :audio::AudioReadError) -> VorbisError {
VorbisError::BadAudio(err)
}
}
impl From<header::HeaderReadError> for VorbisError {
fn from(err :header::HeaderReadError) -> VorbisError {
VorbisError::BadHeader(err)
}
}
#[cfg(feature = "ogg")]
impl From<OggReadError> 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),
}
}

103
vendor/lewton/src/samples.rs vendored Normal file
View File

@@ -0,0 +1,103 @@
// Vorbis decoder written in Rust
//
// Copyright (c) 2019 est31 <MTest31@outlook.com>
// 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<Vec<f32>>) -> Self;
}
impl<S :Sample> Samples for Vec<Vec<S>> {
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<Vec<f32>>) -> 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<S :Sample> {
pub samples :Vec<S>,
pub channel_count :usize,
}
impl<S :Sample> Samples for InterleavedSamples<S> {
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<Vec<f32>>) -> 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...
<Vec<Vec<S>> 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
}
}
}