[
  {
    "path": ".editorconfig",
    "content": "# top-most EditorConfig file\nroot = true\n\n[*]\nindent_style = tab\ntab_width = 4\nend_of_line=lf\ncharset=utf-8\ntrim_trailing_whitespace=true\ninsert_final_newline=true\n"
  },
  {
    "path": ".github/workflows/lewton.yml",
    "content": "name: lewton\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    strategy:\n      matrix:\n        os: [macOS-latest, ubuntu-latest, windows-latest]\n        toolchain: [stable, 1.56.1]\n\n    runs-on: ${{ matrix.os }}\n\n    steps:\n    - uses: actions/checkout@master\n    - name: Install Rust\n      uses: actions-rs/toolchain@v1\n      with:\n        toolchain: ${{ matrix.toolchain }}\n        override: true\n    - name: Run no-default-features builds\n      env:\n        RUSTFLAGS: -D warnings\n      run: |\n        cargo test --verbose --no-default-features\n        cargo doc --verbose --no-default-features\n    - name: Run all-features builds\n      env:\n        RUSTFLAGS: -D warnings\n      run: |\n        cargo test --verbose --all-features\n        cargo doc --verbose --all-features\n    - name: Run cmp tests\n      env:\n        RUSTFLAGS: -D warnings\n      if: (matrix.toolchain == '1.56.1') && (matrix.os != 'windows-latest')\n      run: |\n        sed -i.bak \"/^vorb.*/d;s/#v/v/\" dev/cmp/Cargo.toml\n        cargo update -p vorbis-sys:0.0.8\n        cargo test --verbose --release -p cmp\n"
  },
  {
    "path": ".gitignore",
    "content": "target\n*swp\ncallgrind.out.*\ntest-assets\n"
  },
  {
    "path": ".rustfmt.toml",
    "content": "# Note that this rustfmt file only provides rough\n# guidelines about how the style should be.\n# Right now, rustfmt is not capable to map all\n# demands to the code style (yet).\n\nhard_tabs = true\nnormalize_comments = false\nmax_width = 120\nideal_width = 100\nspace_before_type_annotation = true\nspace_before_bound = false\nspace_after_type_annotation_colon = false\nspace_after_bound_colon = true\nspaces_around_ranges = true\nmatch_block_trailing_comma = true\nmatch_wildcard_trailing_comma = true\nwrap_match_arms = false\nfn_brace_style = \"PreferSameLine\"\nitem_brace_style = \"PreferSameLine\"\nfn_args_layout = \"Block\"\nwhere_pred_indent = \"Block\"\ngenerics_indent = \"Block\"\nstruct_lit_style = \"Block\"\nfn_call_style = \"Block\"\nchain_indent = \"Block\"\ntake_source_hints = true\ntrailing_comma = \"Vertical\"\nfn_args_density = \"Compressed\"\nwhere_density = \"Compressed\"\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changes\n\n## Release 0.10.2 - January 20, 2021\n\n* Updated ogg to 0.8\n* Updated tinyvec to 1.0\n* Testsuite fixes. Thanks to [@nico-abram](https://github.com/nico-abram) for their help!\n\n## Release 0.10.1 - March 16, 2020\n\n* Removed deprecated Error descriptions\n* Swapped smallvec for tinyvec. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the contribution!\n\n## Release 0.10.0 - January 30, 2020\n\n* MSRV increased to 1.36.0. This is mainly because smallvec needs 1.36.0 now.\n* Updated to smallvec 1.0. Thanks to [@repi](https://github.com/repi) for the contribution!\n* C API via cbingen/cargo-c. Thanks to [@lu-zero](https://github.com/lu-zero) for the contribution!\n* Various simplifications in audio.rs. Thanks to [@AnthonyMikh](https://github.com/AnthonyMikh) for the contribution!\n* Moved from Travis CI to Github Actions. Thanks to [@Luni-4](https://github.com/Luni-4) for the contribution!\n* Adopted a workspace to have a common Cargo.lock file.\n\n## Release 0.9.4 - March 08, 2019\n\n* Added a function to obtain the stream serial from an `OggStreamReader`\n* Invalid UTF-8 strings in comment headers are now silently omitted\n* Allowed to specify floats as output format\n* Fixed multiple bugs on fuzzed inputs\n\n## Release 0.9.3 - October 28, 2018\n\n* 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))\n* Updated ogg to 0.7.0\n\n## Release 0.9.2 - October 07, 2018\n\n* Fixed a wrongly decoded file bug (issue [#24](https://github.com/RustAudio/lewton/issues/24))\n\n## Release 0.9.1 - September 22, 2018\n\n* Performance improvements of about 10%. Thanks to [@GabrielMajeri](https://github.com/GabrielMajeri) for the contribution!\n* Fixed some wrongly decoded files\n* Fixed some panics on crafted input. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the fuzzing and bug reports.\n* Added travis CI\n\n## Release 0.9.0 - August 16, 2018\n\n* Renamed `async` to `async_api` for better edition 2018 compilance\n* Updated ogg to 0.6.0\n* Expanded test suite to include xiph test vectors\n* Support for chained files\n\n## Release 0.8.0 - February 7, 2018\n\n* Removed unused error enum variant\n* Pub used OggReadError so that people can match on its variants without needing to depend on the Ogg crate\n* 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.\n\n## Release 0.7.0 - October 24, 2017\n\n* Removed all uses of unsafe in return of making Rust 1.20 required\n\n## Release 0.6.2 - June 18, 2017\n\n* Exposed blockize_0 and blocksize_1 in the public API\n  of the ident header again, so that lewton can be used without ogg encapsulation.\n\n## Release 0.6.1 - June 8, 2017\n\n* Fix a doc link\n\n## Release 0.6.0 - June 8, 2017\n\n* Made parts of the API that are not intended for the public crate local\n* Added seeking support with a granularity of pages\n* Updated to ogg to 0.5.0\n* The async support now doesn't need unstable features any more, and bases on tokio\n\n## Release 0.5.2 - May 13, 2017\n\n* Removed two unused macros to prevent warnings about them\n\n## Release 0.5.1 - April 30, 2017\n\n* Bugfix to work on newest Rust nightly/beta\n* Bugfix to work with the alto crate instead of openal-rs which has been yanked\n* Bugfix in the player example for duration calculation\n\n## Release 0.5 - February 15, 2017\n\n* New, more convenient, constructor for OggStreamReader.\n* Updated to Byteorder 1.0.\n\n## Release 0.4.1 - November 17, 2016\n\n* Fixed a panic issue with reading huffman trees.\n\n## Release 0.4 - October 4, 2016\n\n* Updated ogg.\n* Made the `inside_ogg` API own the reader.\n\n## Release 0.3 - October 4, 2016\n\n* Added support for floor 0. It is not used in practice anymore,\n  but now all features of the vorbis format are supported.\n* Improved the API for reading decoded packets.\n* Fixed a bug in comment header parsing.\n* Various minor simplifications.\n* Improved the cmp tool. You can now compare our output to libvorbis\n  with `cargo test --release -- --nocapture`,\n  and our speed with `cargo run --release bench`.\n\n## Release 0.2 - September 13, 2016\n\n* Improved speed by about 20%.\n* Added async ready API to the `inside_ogg` module to work with async IO.\n  Still behind a feature as it relies on the unstable [specialisation feature](https://github.com/rust-lang/rust/issues/31844).\n* Removed parts of the API that were irrelevant to users of the crate.\n  This gives a better overview for our users.\n  Unfortunately due to [pub(crate) not being stable yet](https://github.com/rust-lang/rust/issues/32409),\n  not all parts of the API could have been made private.\n* Examples are CC-0 now, this should ease adoption.\n* Documentation improvements\n* Implemented a tool to compare our speed and output with libvorbis.\n  To see how correct this crate is, cd to `dev/cmp` and do `cargo run --release vals /path/to/test_file.ogg`.\n  For speed tests, swap \"vals\" with \"perf\".\n\n## Release 0.1 - September 1, 2016\n\nInitial release.\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "Cargo.toml",
    "content": "[workspace]\nmembers = [\"dev/cmp\"]\n\n[package]\nname = \"lewton\"\nversion = \"0.10.2\"\nauthors = [\"est31 <MTest31@outlook.com>\"]\ndescription = \"Pure Rust vorbis decoder\"\nlicense = \"MIT OR Apache-2.0\"\nrepository = \"https://github.com/RustAudio/lewton\"\nkeywords = [\"ogg\", \"vorbis\", \"decoder\", \"audio\"]\ncategories = [\"compression\", \"multimedia::audio\", \"multimedia::encoding\"]\ndocumentation = \"https://docs.rs/lewton\"\nreadme = \"README.md\"\nedition = \"2015\"\nrust-version = \"1.56.0\"\n\n[features]\ndefault = [\"ogg\"]\nasync_ogg = [\"ogg\", \"ogg/async\", \"futures\", \"tokio-io\"]\ncapi = []\n\n[[example]]\nname = \"perf\"\nrequired-features = [\"ogg\"]\n\n[[example]]\nname = \"player\"\nrequired-features = [\"ogg\"]\n\n[dependencies]\nbyteorder = \"1.0\"\ntinyvec = { version = \"1.0\", features = [\"alloc\"] }\nogg = { version = \"0.8\", optional = true }\ntokio-io = { version = \"0.1\", optional = true }\nfutures = { version = \"0.1\", optional = true }\n\n[dev-dependencies]\nogg = \"0.8\"\nalto = \"3\"\n\n[package.metadata.docs.rs]\nfeatures = [\"async_ogg\"]\n\n[lib]\nname = \"lewton\"\n"
  },
  {
    "path": "LICENSE",
    "content": "Copyright (c) 2016 est31 <MTest31@outlook.com> and contributors\n\nLicensed under MIT or Apache License 2.0,\nat your option.\n\nThe full list of contributors can be obtained by looking\nat the VCS log (originally, this crate was git versioned,\nthere you can do \"git shortlog -sn\" for this task).\n\nMIT License\n-----------\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 est31 <MTest31@outlook.com> and contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n\n\nApache License, version 2.0\n---------------------------\n                                 Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n"
  },
  {
    "path": "README.md",
    "content": "# lewton\n\n[![docs](https://docs.rs/lewton/badge.svg)](https://docs.rs/crate/lewton)\n[![crates.io](https://img.shields.io/crates/v/lewton.svg)](https://crates.io/crates/lewton)\n[![dependency status](https://deps.rs/repo/github/rustaudio/lewton/status.svg)](https://deps.rs/repo/github/rustaudio/lewton)\n\nVorbis decoder written in pure Rust.\n\nTo give the decoder a try, you can do:\n```sh\ncargo run --example player /path/to/your/audio_file.ogg\n```\nIt will then play back the audio.\n\nIf you want to know how to use this crate, look at the examples folder.\n\nThis crate has a low level API for per-packet decoding in the `audio` and `header` modules,\nand a high level API for ogg/vorbis streams in the `inside_ogg` module.\n\nSome parts were created with help from the public domain\n[stb_vorbis](http://nothings.org/stb_vorbis/) decoder implementation.\n\nThe minimum required Rust version is 1.56.\n\n## Use of unsafe\n\nThe entire library uses not a single line of unsafe code.\nIn fact, lib.rs contains the `#![forbid(unsafe_code)]` directive.\n\n## About the history of this crate\n\nI started to work on this crate in December 2015.\nThe goal was to learn more about Rust and audio processing,\nwhile also delivering something useful to the Rust ecosystem.\n\nI've tried not to look into the libvorbis implementation,\nas then I'd have to first abide the BSD license, and second\nas I didn't want this crate to become \"just\" a translation\nfrom C to Rust. Instead I wanted this crate to base on the\nspec only, so that I'd learn more about how vorbis worked.\n\nThe only time I did look into the libvorbis implementation\nwas to look up the implementation of a function needed by\nthe ogg crate (the CRC function), which is why that crate\nis BSD licensed, and attributes the authors.\nThis crate however contains no code, translated or\notherwise, from the libvorbis implementation.\n\nAfter some time I realized that without any help of a working\nimplementation progress would become too slow.\n\nTherefore, I've continued to work with the public domain\n`stb_vorbis` implementation and used some of its\ncode (most prominently for the imdct algorithm) to\ntranslate it to rust. I've also used it for debugging by\ncomparing its outputs with mine.\n\nMost of this crate however was created by reading the spec\nonly.\n\n## Use from C\n**lewton** provides a C-compatible set of library, header and pkg-config file.\n\nTo build and install it you can use [cargo-c](https://crates.io/crates/cargo-c):\n\n```sh\ncargo install cargo-c\ncargo cinstall --release --destdir /tmp/lewton\nsudo cp -a /tmp/lewton/* /\n```\n\n## License\n\nLicensed under Apache 2 or MIT (at your option). For details, see the [LICENSE](LICENSE) file.\n\nAll examples inside the `examples/` folder are licensed under the\n[CC-0](https://creativecommons.org/publicdomain/zero/1.0/) license.\n\n### License of your contributions\n\nUnless you explicitly state otherwise, any contribution intentionally submitted for\ninclusion in the work by you, as defined in the Apache-2.0 license,\nshall be dual licensed / CC-0 licensed as above, without any additional terms or conditions.\n"
  },
  {
    "path": "cbindgen.toml",
    "content": "header = \"// SPDX-License-Identifier: MIT OR Apache-2.0\"\nsys_includes = [\"stddef.h\", \"stdint.h\", \"stdlib.h\"]\nno_includes = true\ninclude_guard = \"LEWTON_LEWTON_H\"\ntab_width = 4\nstyle = \"Type\"\nlanguage = \"C\"\n"
  },
  {
    "path": "dev/cmp/Cargo.toml",
    "content": "[package]\nname = \"cmp\"\npublish = false\nversion = \"0.1.0\"\nlicense = \"MIT OR Apache-2.0\"\nauthors = [\"est31 <MTest31@outlook.com>\"]\nedition = \"2015\"\n\n[dependencies]\nlewton = { path = \"../../\" }\nvorbis = \"0.1\"\n# Workaround for test failure.\n# Apply branch of this PR: https://github.com/tomaka/vorbis-rs/pull/20\n#vorbis = { git = 'https://github.com/roderickvd/vorbis-rs', branch = 'fix-ub-panic' }\ntest-assets = \"0.2\"\n"
  },
  {
    "path": "dev/cmp/src/lib.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016-2017 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\nextern crate lewton;\nextern crate vorbis;\nextern crate test_assets;\n\nuse std::fs::File;\n\nuse lewton::inside_ogg::*;\nuse lewton::header::{IdentHeader, CommentHeader, SetupHeader};\nuse std::time::{Duration, Instant};\nuse std::io::{Cursor, Read, Seek};\n\nuse vorbis::Decoder as NativeDecoder;\n\npub fn cmp_perf(file_path :&str) -> (Duration, Duration, usize) {\n\tmacro_rules! try {\n\t\t($expr:expr) => (match $expr {\n\t\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t\t$crate::std::result::Result::Err(err) => {\n\t\t\t\tpanic!(\"Error: {:?}\", err)\n\t\t\t}\n\t\t})\n\t}\n\n\t// Read the file to memory to create fairer playing ground\n\tlet mut f = try!(File::open(file_path));\n\tlet mut file_buf = Vec::new();\n\ttry!(f.read_to_end(&mut file_buf));\n\n\tlet r_n = Cursor::new(&file_buf);\n\tlet start_native_decode = Instant::now();\n\tlet dec = try!(NativeDecoder::new(r_n));\n\tlet mut native_it = dec.into_packets();\n\tloop {\n\t\ttry!(match native_it.next() {\n\t\t\tSome(v) => v,\n\t\t\tNone => break,\n\t\t});\n\t}\n\tlet native_decode_duration = Instant::now() - start_native_decode;\n\n\tlet mut n = 0;\n\tlet r_r = Cursor::new(&file_buf);\n\tlet start_decode = Instant::now();\n\tlet mut ogg_rdr = try!(OggStreamReader::new(r_r));\n\n\t// Reading and discarding the first empty packet\n\t// The native decoder does this itself.\n\ttry!(ogg_rdr.read_dec_packet());\n\n\twhile let Some(_) = try!(ogg_rdr.read_dec_packet()) {\n\t\tn += 1;\n\t}\n\tlet decode_duration = Instant::now() - start_decode;\n\treturn (decode_duration, native_decode_duration, n);\n}\n\npub fn cmp_file_output(file_path :&str) -> (usize, usize) {\n\tmacro_rules! try {\n\t\t($expr:expr) => (match $expr {\n\t\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t\t$crate::std::result::Result::Err(err) => {\n\t\t\t\tpanic!(\"Error: {:?}\", err)\n\t\t\t}\n\t\t})\n\t}\n\tlet f = try!(File::open(&file_path));\n\tlet f_2 = try!(File::open(&file_path));\n\ttry!(cmp_output(f, f_2, |u, v, _, _, _, _, _| (u, v)))\n}\n\npub fn cmp_output<R :Read + Seek, T, F :Fn(usize, usize, usize,\n\t\tbool,\n\t\t&IdentHeader, &CommentHeader, &SetupHeader)->T>(\n\t\trdr :R, rdr_2 :R, f :F) -> Result<T, String> {\n\tmacro_rules! try {\n\t\t($expr:expr) => (match $expr {\n\t\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t\t$crate::std::result::Result::Err(err) => {\n\t\t\t\treturn Err(format!(\"{:?}\", err))\n\t\t\t}\n\t\t})\n\t}\n\tlet f_n = rdr;\n\tlet f_r = rdr_2;\n\n\tlet dec = try!(NativeDecoder::new(f_n));\n\n\tlet mut ogg_rdr = try!(OggStreamReader::new(f_r));\n\tlet stream_serial = ogg_rdr.stream_serial();\n\n\t// Now the fun starts..\n\tlet mut native_it = dec.into_packets();\n\tlet mut n = 0;\n\n\t// Reading and discarding the first empty packet\n\t// The native decoder does this itself.\n\ttry!(ogg_rdr.read_dec_packet());\n\n\tlet mut pcks_with_diffs = 0;\n\n\t// This parameter is useful when we only want to check whether the\n\t// actually returned data are the same, regardless of where the\n\t// two implementations put packet borders.\n\t// Of course, when debugging bugs which modify the size of packets\n\t// you usually want to set this flag to false so that you don't\n\t// suffer from the \"carry over\" effect of errors.\n\tlet ignore_packet_borders :bool = true;\n\n\tlet mut native_dec_data = Vec::new();\n\tlet mut dec_data = Vec::new();\n\n\tlet mut total_sample_count = 0;\n\n\tlet mut chained_ogg_file = false;\n\tloop {\n\t\tn += 1;\n\n\t\tlet mut native_decoded = try!(match native_it.next() { Some(v) => v,\n\t\t\tNone => break,});\n\t\tnative_dec_data.extend_from_slice(&mut native_decoded.data);\n\t\tlet mut pck_decompressed = match try!(ogg_rdr.read_dec_packet_itl()) {\n\t\t\tSome(v) => v,\n\t\t\tNone => break, // TODO tell calling code about this condition\n\t\t};\n\n\t\t// Asserting some very basic things:\n\t\tassert_eq!(native_decoded.rate, ogg_rdr.ident_hdr.audio_sample_rate as u64);\n\t\tassert_eq!(native_decoded.channels, ogg_rdr.ident_hdr.audio_channels as u16);\n\n\t\ttotal_sample_count += pck_decompressed.len();\n\t\tif stream_serial != ogg_rdr.stream_serial() {\n\t\t\t// Chained ogg file\n\t\t\tchained_ogg_file = true;\n\t\t}\n\n\t\t// Fill dec_data with stuff from this packet\n\n\t\tdec_data.extend_from_slice(&mut pck_decompressed);\n\n\t\tlet mut diffs = 0;\n\t\tfor (s,n) in dec_data.iter().zip(native_dec_data.iter()) {\n\t\t\tlet diff = *s as i32 - *n as i32;\n\t\t\t// +- 2 deviation is allowed.\n\t\t\tif diff.abs() > 2 {\n\t\t\t\tdiffs += 1;\n\t\t\t}\n\t\t}\n\n\t\tlet native_dec_len = native_dec_data.len();\n\t\tlet dec_len = dec_data.len();\n\n\t\tif diffs > 0 || (!ignore_packet_borders && dec_len != native_dec_len) {\n\t\t\t/*\n\t\t\tprint!(\"Differences found in packet no {}... \", n);\n\t\t\tprint!(\"ours={} native={}\", dec_len, native_dec_len);\n\t\t\tprintln!(\" (diffs {})\", diffs);\n\t\t\t*/\n\t\t\tpcks_with_diffs += 1;\n\t\t}\n\n\t\tif ignore_packet_borders {\n\t\t\tnative_dec_data.drain(..std::cmp::min(native_dec_len, dec_len));\n\t\t\tdec_data.drain(..std::cmp::min(native_dec_len, dec_len));\n\t\t} else {\n\t\t\tnative_dec_data.truncate(0);\n\t\t\tdec_data.truncate(0);\n\t\t}\n\t}\n\treturn Ok(f(pcks_with_diffs, n, total_sample_count,\n\t\tchained_ogg_file,\n\t\t&ogg_rdr.ident_hdr, &ogg_rdr.comment_hdr, &ogg_rdr.setup_hdr));\n}\n\n/// Like try, but performs an action if an \"expected\" error\n/// is intercepted\n#[macro_export]\nmacro_rules! try_expected {\n\t($expr:expr, $expected:pat, $action:tt) => (match $expr {\n\t\tOk(val) => val,\n\t\tErr($expected) => {\n\t\t\t$action\n\t\t},\n\t\tErr(e) => {\n\t\t\tpanic!(\"Unexpected error: {:?}\\nExpected: {:?}\", e, stringify!($type));\n\t\t},\n\t})\n}\n\n/// Ensures that a file is malformed and returns an error,\n/// but doesn't panic or crash or anything of the like\n#[macro_export]\nmacro_rules! ensure_malformed {\n\t($name:expr, $expected:pat) => {{\n\t\tuse std::fs::File;\n\t\tuse lewton::inside_ogg::OggStreamReader;\n\t\t// Read the file to memory\n\t\tlet f = File::open(format!(\"test-assets/{}\", $name)).unwrap();\n\t\tif let Some(mut ogg_rdr) = try_expected!(OggStreamReader::new(f).map(|v| Some(v)), $expected, None) {\n\t\t\tloop {\n\t\t\t\tmatch try_expected!(ogg_rdr.read_dec_packet_itl(), $expected, break) {\n\t\t\t\t\tSome(_) => (),\n\t\t\t\t\tNone => panic!(\"File {} decoded without errors\", $name),\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}}\n}\n\n/// Ensures that a file decodes without errors\n#[macro_export]\nmacro_rules! ensure_okay {\n\t($name:expr) => {{\n\t\tuse std::fs::File;\n\t\tuse lewton::inside_ogg::OggStreamReader;\n\t\t// Read the file to memory\n\t\tlet f = File::open(format!(\"test-assets/{}\", $name)).unwrap();\n\t\tif let Some(mut ogg_rdr) = OggStreamReader::new(f).map(|v| Some(v)).unwrap() {\n\t\t\tloop {\n\t\t\t\tmatch ogg_rdr.read_dec_packet_itl().unwrap() {\n\t\t\t\t\tSome(_) => (),\n\t\t\t\t\tNone => break,\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t}}\n}\n\nuse self::test_assets::TestAssetDef;\n\npub fn get_asset_defs() -> [TestAssetDef; 6] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bwv_1043_vivace.ogg\"),\n\t\t\thash : format!(\"839249e46220321e2bbb1106e30d0bef4acd800d3827a482743584f313c8c671\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/bwv_1043_vivace.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bwv_543_fuge.ogg\"),\n\t\t\thash : format!(\"c5de55fe3613a88ba1622a1c931836c0af5e9bf3afae951418a07975a16e7421\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/bwv_543_fuge.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"maple_leaf_rag.ogg\"),\n\t\t\thash : format!(\"f66f18de6bc79126f13d96831619d68ddd56f9527e50e1058be0754b479ee350\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/maple_leaf_rag.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"hoelle_rache.ogg\"),\n\t\t\thash : format!(\"bbdf0a8d4c151aee5a21fb71ed86894b1aae5c7dba9ea767f7af6c0f752915c2\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/hoelle_rache.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"thingy-floor0.ogg\"),\n\t\t\thash : format!(\"02b9e94764db30b876964eba2d0a813dedaecdbfa978a13dc9cef9bdc1f4e9ee\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/thingy-floor0.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"audio_simple_err.ogg\"),\n\t\t\thash : format!(\"1b97b2b151b34f1ca6868aa0088535792252aa5c7c990e1de9eedd6a33d3c0dd\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/1543593/audio_simple_err.zip\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_libnogg_asset_defs() -> [TestAssetDef; 32] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6-mode-bits-multipage.ogg\"),\n\t\t\thash : format!(\"e68f06c58a8125933d869d4c831ee298500b1894ab27dc4841f075c104093c27\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6-mode-bits-multipage.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6-mode-bits.ogg\"),\n\t\t\thash : format!(\"48ec7d1b3284ea8cdb9a3511f4f1dd4d8170be9482dd7c0e8edb49802318e1c8\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6-mode-bits.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6ch-all-page-types.ogg\"),\n\t\t\thash : format!(\"c965f1f03be8af3869d22fcad41bbde0111ba18748f7c9b27fb46e4a33b857cd\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-all-page-types.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6ch-long-first-packet.ogg\"),\n\t\t\thash : format!(\"7ac5d89b9cc69762dd191d17778b0625462d4a2c5488d10e8aef6a77e990c7f7\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-long-first-packet.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6ch-moving-sine-floor0.ogg\"),\n\t\t\thash : format!(\"95443ad7c16f3dc7f66ce34aeb3ec90f14fb717c79326e8f3c92826f5c0606e1\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-moving-sine-floor0.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"6ch-moving-sine.ogg\"),\n\t\t\thash : format!(\"05dae404fc266671598aaf2fd55f52d563e7f26631abbd3487cc9b63d458500d\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-moving-sine.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bad-continued-packet-flag.ogg\"),\n\t\t\thash : format!(\"8c93b1ec92746b4c9eb8c855e65218f14cd8c3024ddea5b3264c8a66fee7d6ee\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bad-continued-packet-flag.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bitrate-123.ogg\"),\n\t\t\thash : format!(\"8cbb82b8eab2e4d4115b62f62323c85d05e2352519677996d7a1e53c01ebb436\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-123.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bitrate-456-0.ogg\"),\n\t\t\thash : format!(\"2ae12b963c333164f1fbbbf4fc75bc9aa6b5b4289a9791ba9a3a7c275d725571\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-456-0.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bitrate-456-789.ogg\"),\n\t\t\thash : format!(\"326bb289c1dcc4f79ee007199a8124dd14bfea4a1f7fb94f9c7f9394c0b53584\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-456-789.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"empty-page.ogg\"),\n\t\t\thash : format!(\"51010e14b84dee562b76d3a4ddb760d4b3a740d78714b11b6307e2de73ee6d48\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/empty-page.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"large-pages.ogg\"),\n\t\t\thash : format!(\"53b63f9661ddf726bd0b9d1933b7fe54ef10248742354ff215b294f34ac0aec0\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/large-pages.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"long-short.ogg\"),\n\t\t\thash : format!(\"96a166446ee171f9df3b7a4701567d19e52d8cfc593e17ca4f8697dde551de63\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/long-short.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"noise-6ch.ogg\"),\n\t\t\thash : format!(\"879ab419c0a848b0d17b1d6b9d8557c4cec35ffb0d973371743eeee70c6f7e17\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/noise-6ch.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"noise-stereo.ogg\"),\n\t\t\thash : format!(\"53c9e52bf47f89d292644e4cd467da70c49709fdcc7a2c99d171b4e1883a0499\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/noise-stereo.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"partial-granule-position.ogg\"),\n\t\t\thash : format!(\"d42765b76989a74fc9071d082409a34e9a4c603eecb51b253d4d026a9751580e\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/partial-granule-position.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"sample-rate-max.ogg\"),\n\t\t\thash : format!(\"c758248cdc2d2ed67ed80f27e8436565fd5b94c5c662a88ab9a5fabd6d23ff04\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sample-rate-max.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"single-code-2bits.ogg\"),\n\t\t\thash : format!(\"ee1eb710f37709fea87d1fac6cdb6ab86012497c50dae58d237b6607165656b9\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-2bits.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"single-code-nonsparse.ogg\"),\n\t\t\thash : format!(\"9fbbbe8ba4988d8362a66f4252fe8f528e41ac659db23f377a9166bba843bb7b\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-nonsparse.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"single-code-ordered.ogg\"),\n\t\t\thash : format!(\"27e53ee98f2773405b98f6ad402aad2d0be3d3fd7439acab720f46c73957bc93\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-ordered.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"single-code-sparse.ogg\"),\n\t\t\thash : format!(\"3327a0eb7287bc2df2a10932446930c9da6fa3383b0a63a81cfd04f832e160a6\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-sparse.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"sketch008-floor0.ogg\"),\n\t\t\thash : format!(\"64fc1efe12609a0544448021c730c2832a758637982a4698a138f138a1417b5c\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch008-floor0.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"sketch008.ogg\"),\n\t\t\thash : format!(\"d0b34d94a5379edc6eb633743ecd187d81b02e5354fed989f35320ecfd32be71\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch008.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"sketch039.ogg\"),\n\t\t\thash : format!(\"c595bec5d9bad0103527f779dba13837743866c15ff5ad7aeedc6dab49516d9a\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch039.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"split-packet.ogg\"),\n\t\t\thash : format!(\"e5e5598845d733a1efaeb258a6c07563af8dd30204117044d25df13cd2944e0e\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/split-packet.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"square-interleaved.ogg\"),\n\t\t\thash : format!(\"305a703187f5ad84facbf5b8990007cfe93d4035e3efb9f86014967604374356\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-interleaved.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"square-multipage.ogg\"),\n\t\t\thash : format!(\"691988c4fefe850dd265fd8c91f2e90c92f94578ce18c8005b40e88277dc26c9\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-multipage.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"square-stereo.ogg\"),\n\t\t\thash : format!(\"b2eb353cdd9ddd3f809647474e1a8bff6913e28b53cac52a54906f7ff203501f\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-stereo.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"square-with-junk.ogg\"),\n\t\t\thash : format!(\"51ede72de15b2998cf8de6dd3f57a6abc280f9278d775f0f5fec2d2679e341b6\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-with-junk.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"square.ogg\"),\n\t\t\thash : format!(\"31c9fa7d2f374ebf9ffc1c21e95b8369c2ced3ae230151c00208613ca308d812\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square.ogg\"),\n\t\t},\n\t\t// Omit thingy-floor0.ogg\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"thingy.ogg\"),\n\t\t\thash : format!(\"646f05235723aa09e69e123c73560ffb753f9ffe00e3c54b99f8f0c1cd583707\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/thingy.ogg\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"zero-length.ogg\"),\n\t\t\thash : format!(\"aa71c87218f6dec51383110bc1b77d204bbb21f7867e2cc8283042417522b330\"),\n\t\t\turl : format!(\"http://achurch.org/hg/libnogg/raw-file/tip/tests/data/zero-length.ogg\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_xiph_asset_defs_1() -> [TestAssetDef; 5] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"1.0-test.ogg\"),\n\t\t\thash : format!(\"9a882710314bcc1d2b4cdefb7f89911f4375acd1feb9e64a12eca9f7202377d3\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/1.0-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"1.0.1-test.ogg\"),\n\t\t\thash : format!(\"8c9423e00826d6d2457d78c09d6e2a94bcdf9216af796bb22a4c4f450c2e72bb\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/1.0.1-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"48k-mono.ogg\"),\n\t\t\thash : format!(\"f51459d9bdd04ca3ec6f6732b8a01efcdc83e5c6fc79c7d5347527bfd4948e9e\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/48k-mono.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"beta3-test.ogg\"),\n\t\t\thash : format!(\"7fc791a4d5a0d3b7cef2448093ccf2ae54600acc81667be90c6b209c366c32ea\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/beta3-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"beta4-test.ogg\"),\n\t\t\thash : format!(\"bc367c0d4dcdbf1f0a2f81abf74cc52c8f0ab8366d150a75830782ca2dba080a\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/beta4-test.ogg?raw=true\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_xiph_asset_defs_2() -> [TestAssetDef; 5] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bimS-silence.ogg\"),\n\t\t\thash : format!(\"e2a38871d390ed651faf0fec5253a6873530da4f2503d85021c99325dfd23813\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/bimS-silence.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"chain-test1.ogg\"),\n\t\t\thash : format!(\"d9c37533a1f456d2a996755a43d112ef46b6ef953319913907bc79f1c014d79e\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test1.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"chain-test2.ogg\"),\n\t\t\thash : format!(\"5b5bf834e93e9a93b7114be084161e972f33d2031963518492ba2c91dc4418a7\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test2.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"chain-test3.ogg\"),\n\t\t\thash : format!(\"ed039ba775d1b31e805d26d6413a3ef2c6663bf4c5ea47ce1462f8f23c84d8dc\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test3.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"highrate-test.ogg\"),\n\t\t\thash : format!(\"0942c88369f84b125388cc8437575b66d67bc97baaeeb997b6602144821509df\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/highrate-test.ogg?raw=true\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_xiph_asset_defs_3() -> [TestAssetDef; 5] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"lsp-test.ogg\"),\n\t\t\thash : format!(\"ad1b07b68576ae2c85178475ef3607e1a96c09e96296cae83ee7a9726f8311eb\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"lsp-test2.ogg\"),\n\t\t\thash : format!(\"7b00f893a93071bdf243b8a22c1758a6ab09c1ab8eee89ca21659d98ec0f53ea\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test2.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"lsp-test3.ogg\"),\n\t\t\thash : format!(\"7a5c4064fc31285f6fea0b2424a0d415a8b18ef13d1aa1ef931a429ab9a593d1\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test3.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"lsp-test4.ogg\"),\n\t\t\thash : format!(\"cb0b28931dfc8ef8b2d320f3028fab548171e7c6e94006f0c23532478a8d3596\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test4.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"mono.ogg\"),\n\t\t\thash : format!(\"d8abca95445a07186c9a158d4f573f38918985dd2498a9bc8d1811bd72fe1d1a\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/mono.ogg?raw=true\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_xiph_asset_defs_4() -> [TestAssetDef; 7] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"moog.ogg\"),\n\t\t\thash : format!(\"bd5b51bb1d6855e0e990e3ebdd230fc16265407809bd6db44aea691ada498943\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/moog.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"one-entry-codebook-test.ogg\"),\n\t\t\thash : format!(\"789b5146f2a7c0864a228ee4a870606a32c4169e22097be65129623705c54749\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/one-entry-codebook-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"out-of-spec-blocksize.ogg\"),\n\t\t\thash : format!(\"0970e66291744815f2ca0dec7523f5bbc112907c5c75978a0f91d3b0ed6f03b2\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/out-of-spec-blocksize.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"rc1-test.ogg\"),\n\t\t\thash : format!(\"ccfac6ac7c75615bec0632b94bcf088c027c0b112cd136c997d04f037252cd3d\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc1-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"rc2-test.ogg\"),\n\t\t\thash : format!(\"4adcda786dfeea4188d7b1df35571dbe29c687f2d1cac680ed115353abfe1637\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc2-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"rc2-test2.ogg\"),\n\t\t\thash : format!(\"24ade471eefe1c7642f73a6810e56266b34c2d7d30a3b5ad05a34c098128226c\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc2-test2.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"rc3-test.ogg\"),\n\t\t\thash : format!(\"edd984e84c7c2a59af7801f3e8d2db11a6619134fd8d0274d1289e70bf60cde7\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc3-test.ogg?raw=true\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\npub fn get_xiph_asset_defs_5() -> [TestAssetDef; 5] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"singlemap-test.ogg\"),\n\t\t\thash : format!(\"50d8077608a4192b8f8505aec0217be8b6c25def4068899afc19c17f30e1d521\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/singlemap-test.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"sleepzor.ogg\"),\n\t\t\thash : format!(\"01c67ecaf7a58b5ac5f1fe3bd060b5d61536595e97927a1b1cf0129a62b5cfcf\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/sleepzor.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"test-short.ogg\"),\n\t\t\thash : format!(\"183510552403021fb90ce43796fcc88e16c8bb4ae5d0d72a316b8e51afc395fa\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/test-short.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"test-short2.ogg\"),\n\t\t\thash : format!(\"6bd3f59e0fa77904edd35c73dadd6558e2a36d78c9d7bc5db223862bf092fcc2\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/test-short2.ogg?raw=true\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"unused-mode-test.ogg\"),\n\t\t\thash : format!(\"e27ae6fc2f7c0037c28328801c46d966abcee3050e3ebd40bf097f7986f50f94\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/unused-mode-test.ogg?raw=true\"),\n\t\t},\n\t];\n}\n\n#[allow(unused)]\n/// Regression tests for bugs obtained by fuzzing\n///\n/// The test files are licensed under CC-0:\n/// * https://github.com/RustAudio/lewton/issues/33#issuecomment-419640709\n/// * http://web.archive.org/web/20180910135020/https://github.com/RustAudio/lewton/issues/33\npub fn get_fuzzed_asset_defs() -> [TestAssetDef; 12] {\n\treturn [\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"27_really_minimized_testcase_crcfix.ogg\"),\n\t\t\thash : format!(\"83f6d6f36ae926000f064007e79ef7c45ed561e49223d9b68f980d264050d683\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2363013/27_really_minimized_testcase_crcfix.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"32_minimized_crash_testcase.ogg\"),\n\t\t\thash : format!(\"644170ccc3e48f2e2bf28cadddcd837520df09671c3d3d991b128b9fdb281da6\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2363080/32_minimized_crash_testcase.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"33_minimized_panic_testcase.ogg\"),\n\t\t\thash : format!(\"4812e725d7c6bdb48e745b4e0a396efc96ea5cb30e304cf9710dadda3d963171\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2363173/33_minimized_panic_testcase.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"35_where_did_my_memory_go_repacked.ogg\"),\n\t\t\thash : format!(\"2f202e71ca0440a2de4a15443beae9d3230e81e47bc01d29929fc86ee731887c\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2889595/35_where-did-my-memory-go-repacked.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-42-sample009.ogg\"),\n\t\t\thash : format!(\"7e3d7fd6d306cd1c1704d0586b4e62cc897c499e3ffc1911f62ec0fc3a062871\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2905014/bug-42-sample009.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-42-sample012.ogg\"),\n\t\t\thash : format!(\"8d92c4359bbe987b77459f309859b6bba0a11724e71fd5e81873c597ec71d857\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2905017/bug-42-sample012.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-42-sample015.ogg\"),\n\t\t\thash : format!(\"274c17222d7cfc1044d2fee3e60377eac87f5ee8d952eeaf3d636b016b1db7d3\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2905018/bug-42-sample015.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-42-sample016.ogg\"),\n\t\t\thash : format!(\"ab02fd55a275b1ec0c6c56a667834231bf34b3a79038f43196d1015c1555e535\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2905019/bug-42-sample016.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-42-sample029.ogg\"),\n\t\t\thash : format!(\"1436fff4d8fa61ff2b22ffd021c2bd80f072556b8b58cfc72fdfc0434efd9a24\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2905020/bug-42-sample029.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-44-sample059.ogg\"),\n\t\t\thash : format!(\"4c1452e387a64090465132724a83f02846457336fa58ddc6ee9c6df598d756c0\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2922511/bug-44-sample059.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-44-sample060.ogg\"),\n\t\t\thash : format!(\"b8bd42831a8922c4c78ff1ea5b42ecbb874135ba7e7fcd60c4fff7a419d857a4\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2922512/bug-44-sample060.ogg.zip\"),\n\t\t},\n\t\tTestAssetDef {\n\t\t\tfilename : format!(\"bug-46-sample001.ogg\"),\n\t\t\thash : format!(\"d5015f9a3b79a28bf621ecc2e96286c20ef742e936e256f77b8978e6bce66aad\"),\n\t\t\turl : format!(\"https://github.com/RustAudio/lewton/files/2923287/bug-46-sample001.ogg.zip\"),\n\t\t},\n\t];\n}\n"
  },
  {
    "path": "dev/cmp/src/main.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\nextern crate lewton;\nextern crate vorbis;\nextern crate test_assets;\n\nuse std::env;\n\nmod lib;\nuse lib::*;\n\nfn main() {\n\tlet command_name = env::args().nth(1).expect(\"No command found.\");\n\tmatch command_name.as_ref() {\n\t\t\"vals\" =>  run_vals(), // Comparison of the output\n\t\t\"perf\" =>  run_perf(), // Comparison of speed\n\t\t\"bench\" =>  run_bench(), // Comparison of the output\n\t\t_ => println!(\"Error: invalid command.\\n\\\n\t\tUsage: <Command> <Filename>. Valid commands are \\\n\t\t'vals' for output comparison, 'perf' for speed comparison, \\\n\t\tand 'bench' for benchmarking a test file suite.\"),\n\t}\n}\n\nfn run_perf() {\n\tlet file_path = env::args().nth(2).expect(\"Please specify a file to open via arg.\");\n\tprintln!(\"Opening file: {}\", file_path);\n\tlet (decode_duration, native_decode_duration, n) = cmp_perf(&file_path);\n\n\tprintln!(\"Time to decode {} packets with libvorbis: {} s\",\n\t\tn, native_decode_duration.as_secs_f64());\n\tprintln!(\"Time to decode {} packets with lewton: {} s\",\n\t\tn, decode_duration.as_secs_f64());\n\tprintln!(\"Ratio of difference: {:.2}x\",\n\t\tdecode_duration.as_secs_f64() /\n\t\tnative_decode_duration.as_secs_f64());\n}\n\nfn run_vals() {\n\tlet file_path = env::args().nth(2).expect(\"Please specify a file to open via arg.\");\n\tprintln!(\"Opening file: {}\", file_path);\n\tlet (pcks_with_diffs, n) = cmp_file_output(&file_path);\n\tif pcks_with_diffs > 0 {\n\t\tprintln!(\"Total number of packets with differences: {} of {} ({}%)\",\n\t\t\tpcks_with_diffs, n, pcks_with_diffs as f32 / n as f32 * 100.0);\n\t} else {\n\t\tprintln!(\"No differences found.\");\n\t}\n}\n\nfn run_bench() {\n\tprintln!(\"\");\n\ttest_assets::download_test_files(&get_asset_defs(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!(\"\");\n\tuse std::time::Duration;\n\tlet mut total_native_time = Duration::from_secs(0);\n\tlet mut total_time = Duration::from_secs(0);\n\tmacro_rules! cmp_perf {\n\t\t($str:expr, $fill:expr) => {\n\t\t\tprint!(\"Comparing speed for {} \", $str);\n\t\t\tlet (decode_duration, native_decode_duration, _) =\n\t\t\t\tcmp_perf(&format!(\"test-assets/{}\", $str));\n\t\t\tlet ratio = decode_duration.as_secs_f64() /\n\t\t\t\tnative_decode_duration.as_secs_f64();\n\t\t\tprintln!(\"{}: libvorbis={:.04}s we={:.4}s difference={:.2}x\",\n\t\t\t\t$fill,\n\t\t\t\tnative_decode_duration.as_secs_f64(),\n\t\t\t\tdecode_duration.as_secs_f64(),\n\t\t\t\tratio);\n\t\t\ttotal_native_time += native_decode_duration;\n\t\t\ttotal_time += decode_duration;\n\t\t};\n\t}\n\tcmp_perf!(\"bwv_1043_vivace.ogg\", \"\");\n\tcmp_perf!(\"bwv_543_fuge.ogg\", \"   \");\n\tcmp_perf!(\"maple_leaf_rag.ogg\", \" \");\n\tcmp_perf!(\"hoelle_rache.ogg\", \"   \");\n\tcmp_perf!(\"thingy-floor0.ogg\", \"  \");\n\tprintln!(\"\");\n\tprintln!(\"Overall time spent for decoding by libvorbis: {:.04}s\",\n\t\ttotal_native_time.as_secs_f64());\n\tprintln!(\"Overall time spent for decoding by us: {:.04}s\",\n\t\ttotal_time.as_secs_f64());\n\tprintln!(\"Overall ratio of difference: {:.2}x\",\n\t\ttotal_time.as_secs_f64() /\n\t\ttotal_native_time.as_secs_f64());\n}\n"
  },
  {
    "path": "dev/cmp/tests/fuzzed.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2018 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\nextern crate test_assets;\n#[macro_use]\nextern crate cmp;\nextern crate lewton;\n\n#[test]\nfn test_malformed_fuzzed() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_fuzzed_asset_defs(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tuse lewton::VorbisError::*;\n\tuse lewton::audio::AudioReadError::*;\n\tuse lewton::header::HeaderReadError::*;\n\n\tensure_malformed!(\"27_really_minimized_testcase_crcfix.ogg\", BadAudio(AudioBadFormat));\n\tensure_malformed!(\"32_minimized_crash_testcase.ogg\", BadHeader(HeaderBadFormat));\n\tensure_malformed!(\"35_where_did_my_memory_go_repacked.ogg\", BadHeader(HeaderBadFormat));\n\n\tensure_malformed!(\"bug-42-sample009.ogg\", BadAudio(AudioBadFormat));\n\tensure_malformed!(\"bug-42-sample012.ogg\", BadAudio(AudioBadFormat));\n\t//ensure_malformed!(\"bug-42-sample015.ogg\", BadAudio(AudioBadFormat));\n\n\tensure_malformed!(\"bug-44-sample059.ogg\", BadHeader(HeaderBadFormat));\n\tensure_malformed!(\"bug-44-sample060.ogg\", BadHeader(HeaderBadFormat));\n\n\tensure_malformed!(\"bug-46-sample001.ogg\", BadAudio(AudioBadFormat));\n}\n\n#[test]\nfn test_okay_fuzzed() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_fuzzed_asset_defs(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tensure_okay!(\"33_minimized_panic_testcase.ogg\");\n\tensure_okay!(\"bug-42-sample016.ogg\");\n\tensure_okay!(\"bug-42-sample029.ogg\");\n}\n"
  },
  {
    "path": "dev/cmp/tests/vals.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\nextern crate test_assets;\nextern crate lewton;\n#[macro_use]\nextern crate cmp;\n\nuse lewton::VorbisError::*;\nuse lewton::header::HeaderReadError::*;\nuse lewton::audio::AudioReadError::*;\n\nmacro_rules! cmp_output {\n\t($str:expr, $max_diff:expr) => {\n\t\tprint!(\"Comparing output for {} \", $str);\n\t\tlet (diff_pck_count, _) = cmp::cmp_file_output(&format!(\"test-assets/{}\", $str));\n\t\tprintln!(\": {} differing packets of allowed {}.\", diff_pck_count, $max_diff);\n\t\tassert!(diff_pck_count <= $max_diff);\n\t};\n}\n\n#[test]\nfn test_vals() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_asset_defs(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"bwv_1043_vivace.ogg\", 0);\n\tcmp_output!(\"bwv_543_fuge.ogg\", 0);\n\tcmp_output!(\"maple_leaf_rag.ogg\", 0);\n\tcmp_output!(\"hoelle_rache.ogg\", 0);\n\tcmp_output!(\"thingy-floor0.ogg\", 0);\n\tcmp_output!(\"audio_simple_err.ogg\", 0);\n}\n\n#[test]\nfn test_libnogg_vals() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_libnogg_asset_defs(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"6-mode-bits-multipage.ogg\", 2);\n\tcmp_output!(\"6-mode-bits.ogg\", 2);\n\tcmp_output!(\"6ch-all-page-types.ogg\", 0);\n\tcmp_output!(\"6ch-long-first-packet.ogg\", 0);\n\tcmp_output!(\"6ch-moving-sine-floor0.ogg\", 0);\n\tcmp_output!(\"6ch-moving-sine.ogg\", 0);\n\t// NOTE: The bad-continued-packet-flag.ogg test is\n\t// actually supposed to return an error in libnogg.\n\t// However, libvorbis doesn't, nor does lewton.\n\t// Given a (slightly) erroneous ogg file where there\n\t// are audio packets following the last header packet,\n\t// we follow libvorbis behaviour and simply ignore those packets.\n\t// Apparently the test case has been created in a way\n\t// where this behaviour doesn't evoke an error from lewton.\n\tcmp_output!(\"bad-continued-packet-flag.ogg\", 0);\n\tcmp_output!(\"bitrate-123.ogg\", 0);\n\tcmp_output!(\"bitrate-456-0.ogg\", 0);\n\tcmp_output!(\"bitrate-456-789.ogg\", 0);\n\tcmp_output!(\"empty-page.ogg\", 0);\n\tcmp_output!(\"large-pages.ogg\", 2);\n\tcmp_output!(\"long-short.ogg\", 2);\n\tcmp_output!(\"noise-6ch.ogg\", 0);\n\tcmp_output!(\"noise-stereo.ogg\", 0);\n\tcmp_output!(\"partial-granule-position.ogg\", 2);\n\t#[cfg(not(target_os = \"windows\"))]\n\tcmp_output!(\"sample-rate-max.ogg\", 0);\n\tensure_malformed!(\"single-code-2bits.ogg\", BadHeader(HeaderBadFormat));\n\t// We can't cmp the output here because native\n\t// libvorbis doesn't accept the file as valid\n\tensure_okay!(\"single-code-nonsparse.ogg\");\n\tensure_okay!(\"single-code-ordered.ogg\");\n\tcmp_output!(\"single-code-sparse.ogg\", 0);\n\t#[cfg(not(target_os = \"macos\"))]\n\tcmp_output!(\"sketch008-floor0.ogg\", 0);\n\tcmp_output!(\"sketch008.ogg\", 0);\n\tcmp_output!(\"sketch039.ogg\", 0);\n\tcmp_output!(\"split-packet.ogg\", 2);\n\tcmp_output!(\"square-interleaved.ogg\", 0);\n\tcmp_output!(\"square-multipage.ogg\", 0);\n\tcmp_output!(\"square-stereo.ogg\", 0);\n\t// This is really more an issue of the ogg crate,\n\t// if it's an issue at all.\n\t// https://github.com/RustAudio/ogg/issues/7\n\t//ensure_malformed!(\"square-with-junk.ogg\", OggError(NoCapturePatternFound));\n\tcmp_output!(\"square.ogg\", 0);\n\tcmp_output!(\"thingy.ogg\", 0);\n\tcmp_output!(\"zero-length.ogg\", 0);\n}\n\n#[test]\nfn test_xiph_vals_1() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_xiph_asset_defs_1(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"1.0-test.ogg\", 0);\n\tcmp_output!(\"1.0.1-test.ogg\", 0);\n\tcmp_output!(\"48k-mono.ogg\", 0);\n\tcmp_output!(\"beta3-test.ogg\", 0);\n\tcmp_output!(\"beta4-test.ogg\", 1);\n}\n\n#[test]\nfn test_xiph_vals_2() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_xiph_asset_defs_2(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"bimS-silence.ogg\", 0);\n\tcmp_output!(\"chain-test1.ogg\", 0);\n\tcmp_output!(\"chain-test2.ogg\", 0);\n\tcmp_output!(\"chain-test3.ogg\", 1);\n\tcmp_output!(\"highrate-test.ogg\", 0);\n}\n\n#[test]\nfn test_xiph_vals_3() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_xiph_asset_defs_3(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"lsp-test.ogg\", 0);\n\tcmp_output!(\"lsp-test2.ogg\", 0);\n\tcmp_output!(\"lsp-test3.ogg\", 0);\n\tcmp_output!(\"lsp-test4.ogg\", 0);\n\tcmp_output!(\"mono.ogg\", 0);\n}\n\n#[test]\nfn test_xiph_vals_4() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_xiph_asset_defs_4(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"moog.ogg\", 0);\n\tcmp_output!(\"one-entry-codebook-test.ogg\", 0);\n\tcmp_output!(\"out-of-spec-blocksize.ogg\", 0);\n\tcmp_output!(\"rc1-test.ogg\", 0);\n\tcmp_output!(\"rc2-test.ogg\", 0);\n\tcmp_output!(\"rc2-test2.ogg\", 0);\n\tcmp_output!(\"rc3-test.ogg\", 0);\n}\n\n#[test]\nfn test_xiph_vals_5() {\n\tprintln!();\n\ttest_assets::download_test_files(&cmp::get_xiph_asset_defs_5(),\n\t\t\"test-assets\", true).unwrap();\n\tprintln!();\n\n\tcmp_output!(\"singlemap-test.ogg\", 0);\n\t#[cfg(not(target_os = \"macos\"))]\n\tcmp_output!(\"sleepzor.ogg\", 0);\n\tcmp_output!(\"test-short.ogg\", 0);\n\tcmp_output!(\"test-short2.ogg\", 0);\n\t// Contains an out of bounds mode index\n\tensure_malformed!(\"unused-mode-test.ogg\", BadAudio(AudioBadFormat));\n}\n"
  },
  {
    "path": "examples/perf.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// This example file is licensed\n// under the CC-0 license:\n// https://creativecommons.org/publicdomain/zero/1.0/\n\nextern crate lewton;\nextern crate byteorder;\n\nfn main() {\n\tmatch run() {\n\t\tOk(_) =>(),\n\t\tErr(err) => println!(\"Error: {}\", err),\n\t}\n}\n\nuse std::env;\nuse lewton::VorbisError;\nuse lewton::inside_ogg::OggStreamReader;\nuse std::fs::File;\nuse std::time::Instant;\n\npub fn run() -> Result<(), VorbisError> {\n\tlet file_path = env::args().nth(1).expect(\"No arg found. Please specify a file to open.\");\n\tprintln!(\"Opening file: {}\", file_path);\n\tlet f = File::open(file_path).expect(\"Can't open file\");\n\n\tlet mut srr = OggStreamReader::new(f)?;\n\n\tprintln!(\"Sample rate: {}\", srr.ident_hdr.audio_sample_rate);\n\n\t// Now the fun starts..\n\tlet mut n = 0;\n\tlet mut len_play = 0.0;\n\tlet start_decode_time = Instant::now();\n\twhile let Some(pck) = srr.read_dec_packet()? {\n\t\tn += 1;\n\t\t// This is guaranteed by the docs\n\t\tassert_eq!(pck.len(), srr.ident_hdr.audio_channels as usize);\n\t\tlen_play += pck[0].len() as f32 / srr.ident_hdr.audio_sample_rate as f32;\n\t}\n\tlet decode_duration = Instant::now() - start_decode_time;\n\tprintln!(\"The piece is {} s long ({} packets).\", len_play, n);\n\tprintln!(\"Decoded in {} s.\", decode_duration.as_secs() as f64 + (decode_duration.subsec_nanos() as f64) / 1_000_000_000.0);\n\n\tOk(())\n}\n"
  },
  {
    "path": "examples/player.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// This example file is licensed\n// under the CC-0 license:\n// https://creativecommons.org/publicdomain/zero/1.0/\n\nextern crate alto;\nextern crate lewton;\nextern crate byteorder;\n\nuse std::env;\nuse lewton::VorbisError;\nuse lewton::inside_ogg::OggStreamReader;\nuse std::fs::File;\nuse std::thread::sleep;\nuse std::time::{Instant, Duration};\nuse alto::{Alto, Mono, Stereo, Source};\n\nfn main() {\n\tmatch run() {\n\t\tOk(_) =>(),\n\t\tErr(err) => println!(\"Error: {}\", err),\n\t}\n}\n\nfn run() -> Result<(), VorbisError> {\n\tlet file_path = env::args().nth(1).expect(\"No arg found. Please specify a file to open.\");\n\tprintln!(\"Opening file: {}\", file_path);\n\tlet f = File::open(file_path).expect(\"Can't open file\");\n\n\t// Prepare the reading\n\tlet mut srr = OggStreamReader::new(f)?;\n\n\t// Prepare the playback.\n\tlet al = Alto::load_default().expect(\"Could not load alto\");\n\tlet device = al.open(None).expect(\"Could not open device\");\n\tlet cxt = device.new_context(None).expect(\"Could not create context\");\n\tlet mut str_src = cxt.new_streaming_source()\n\t\t.expect(\"could not create streaming src\");\n\tlet sample_rate = srr.ident_hdr.audio_sample_rate as i32;\n\n\tif srr.ident_hdr.audio_channels > 2 {\n\t\t// the openal crate can't process these many channels directly\n\t\tprintln!(\"Stream error: {} channels are too many!\", srr.ident_hdr.audio_channels);\n\t}\n\n\tprintln!(\"Sample rate: {}\", srr.ident_hdr.audio_sample_rate);\n\n\t// Now the fun starts..\n\tlet mut n = 0;\n\tlet mut len_play = 0.0;\n\tlet mut start_play_time = None;\n\tlet start_decode_time = Instant::now();\n\tlet sample_channels = srr.ident_hdr.audio_channels as f32 *\n\t\tsrr.ident_hdr.audio_sample_rate as f32;\n\twhile let Some(pck_samples) = srr.read_dec_packet_itl()? {\n\t\tprintln!(\"Decoded packet no {}, with {} samples.\", n, pck_samples.len());\n\t\tn += 1;\n\t\tlet buf = match srr.ident_hdr.audio_channels {\n\t\t\t1 => cxt.new_buffer::<Mono<i16>,_>(&pck_samples, sample_rate),\n\t\t\t2 => cxt.new_buffer::<Stereo<i16>,_>(&pck_samples, sample_rate),\n\t\t\tn => panic!(\"unsupported number of channels: {}\", n),\n\t\t}.unwrap();\n\n\t\tstr_src.queue_buffer(buf).unwrap();\n\n\t\tlen_play += pck_samples.len() as f32 / sample_channels;\n\t\t// If we are faster than realtime, we can already start playing now.\n\t\tif n == 100 {\n\t\t\tlet cur = Instant::now();\n\t\t\tif cur - start_decode_time < Duration::from_millis((len_play * 1000.0) as u64) {\n\t\t\t\tstart_play_time = Some(cur);\n\t\t\t\tstr_src.play();\n\t\t\t}\n\t\t}\n\t}\n\tlet total_duration = Duration::from_millis((len_play * 1000.0) as u64);\n\tlet sleep_duration = total_duration - match start_play_time {\n\t\t\tNone => {\n\t\t\t\tstr_src.play();\n\t\t\t\tDuration::from_millis(0)\n\t\t\t},\n\t\t\tSome(t) => Instant::now() - t,\n\t\t};\n\tprintln!(\"The piece is {} s long.\", len_play);\n\tsleep(sleep_duration);\n\n\tOk(())\n}\n"
  },
  {
    "path": "src/audio.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nAudio packet decoding\n\nThis module decodes the audio packets given to it.\n*/\n\nuse std::error;\nuse std::fmt;\nuse std::cmp::min;\nuse std::iter;\nuse tinyvec::TinyVec;\nuse crate::ilog;\nuse bitpacking::BitpackCursor;\nuse header::{Codebook, Floor, FloorTypeZero, FloorTypeOne,\n\tHuffmanVqReadErr, IdentHeader, Mapping, Residue, SetupHeader};\nuse samples::Samples;\n\n#[derive(Debug, PartialEq, Eq)]\npub enum AudioReadError {\n\tEndOfPacket,\n\tAudioBadFormat,\n\tAudioIsHeader,\n\t/// If the needed memory isn't addressable by us\n\t///\n\t/// This error is returned if a calculation yielded a higher value for\n\t/// an internal buffer size that doesn't fit into the platform's address range.\n\t/// Note that if we \"simply\" encounter an allocation failure (OOM, etc),\n\t/// we do what libstd does in these cases: crash.\n\t///\n\t/// This error is not automatically an error of the format,\n\t/// but rather is due to insufficient decoder hardware.\n\tBufferNotAddressable,\n}\n\n// For the () error type returned by the bitpacking layer\n// TODO that type choice was a bit unfortunate,\n// perhaps one day fix this\nimpl From<()> for AudioReadError {\n\tfn from(_ :()) -> AudioReadError {\n\t\tAudioReadError::EndOfPacket\n\t}\n}\n\nimpl error::Error for AudioReadError {}\n\nimpl fmt::Display for AudioReadError {\n\tfn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {\n\t\tlet description = match self {\n\t\t\tAudioReadError::EndOfPacket => \"End of packet reached.\",\n\t\t\tAudioReadError::AudioBadFormat => \"Invalid audio packet\",\n\t\t\tAudioReadError::AudioIsHeader => \"The vorbis version is not supported\",\n\t\t\tAudioReadError::BufferNotAddressable => \"Requested to create buffer of non-addressable size\",\n\t\t};\n\t\twrite!(fmt, \"{}\", description)\n\t}\n}\n\nenum DecodedFloor<'a> {\n\tTypeZero(Vec<f32>, u64, &'a FloorTypeZero),\n\tTypeOne(Vec<u32>, &'a FloorTypeOne),\n\tUnused,\n}\n\nimpl <'a> DecodedFloor<'a> {\n\tfn is_unused(&self) -> bool {\n\t\tmatch self {\n\t\t\t&DecodedFloor::Unused => true,\n\t\t\t_ => false,\n\t\t}\n\t}\n}\n\nenum FloorSpecialCase {\n\tUnused,\n\tPacketUndecodable,\n}\n\nimpl From<()> for FloorSpecialCase {\n\tfn from(_ :()) -> Self {\n\t\t// () always means end of packet condition in the places\n\t\t// the conversion is used.\n\t\treturn FloorSpecialCase::Unused;\n\t}\n}\n\nimpl From<HuffmanVqReadErr> for FloorSpecialCase {\n\tfn from(e :HuffmanVqReadErr) -> Self {\n\t\tuse ::header::HuffmanVqReadErr::*;\n\t\tuse self::FloorSpecialCase::*;\n\t\tmatch e {\n\t\t\tEndOfPacket => Unused,\n\t\t\t// Undecodable per spec, see paragraph about\n\t\t\t// VQ lookup type zero in section 3.3.\n\t\t\tNoVqLookupForCodebook => PacketUndecodable,\n\t\t}\n\t}\n}\n\n// Note that the output vector contains the cosine values of the coefficients,\n// not the bare values like in the spec. This is in order to optimize.\nfn floor_zero_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],\n\t\tfl :&FloorTypeZero) -> Result<(Vec<f32>, u64), FloorSpecialCase> {\n\t// TODO this needs to become 128 bits wide, not just 64,\n\t// as floor0_amplitude_bits can be up to 127.\n\tlet amplitude = try!(rdr.read_dyn_u64(fl.floor0_amplitude_bits));\n\tif amplitude <= 0 {\n\t\t// This channel is unused in this frame,\n\t\t// its all zeros.\n\t\treturn Err(FloorSpecialCase::Unused);\n\t}\n\n\tlet booknumber = try!(rdr.read_dyn_u32(\n\t\tilog(fl.floor0_number_of_books as u64)));\n\tmatch fl.floor0_book_list.get(booknumber as usize) {\n\t\t// Undecodable per spec\n\t\tNone => try!(Err(FloorSpecialCase::PacketUndecodable)),\n\t\tSome(codebook_idx) => {\n\t\t\tlet mut coefficients = Vec::with_capacity(fl.floor0_order as usize);\n\t\t\tlet mut last = 0.0;\n\t\t\tlet codebook = &codebooks[*codebook_idx as usize];\n\t\t\tloop {\n\t\t\t\tlet mut last_new = last;\n\t\t\t\tlet temp_vector = try!(rdr.read_huffman_vq(codebook));\n\t\t\t\tif temp_vector.len() + coefficients.len() < fl.floor0_order as usize {\n\t\t\t\t\t// Little optimisation: we don't have to care about the >= case here\n\t\t\t\t\tfor &e in temp_vector {\n\t\t\t\t\t\tcoefficients.push((last + e as f32).cos());\n\t\t\t\t\t\tlast_new = e as f32;\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tfor &e in temp_vector {\n\t\t\t\t\t\tcoefficients.push((last + e as f32).cos());\n\t\t\t\t\t\tlast_new = e as f32;\n\t\t\t\t\t\t// This rule makes sure that coefficients doesn't get\n\t\t\t\t\t\t// larger than floor0_order and saves an allocation\n\t\t\t\t\t\t// in this case\n\t\t\t\t\t\tif coefficients.len() == fl.floor0_order as usize {\n\t\t\t\t\t\t\treturn Ok((coefficients, amplitude));\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlast += last_new;\n\t\t\t\tif coefficients.len() >= fl.floor0_order as usize {\n\t\t\t\t\treturn Ok((coefficients, amplitude));\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t}\n\tunreachable!();\n}\n\nfn floor_zero_compute_curve(cos_coefficients :&[f32], amplitude :u64,\n\t\tfl :&FloorTypeZero, blockflag :bool, n :u16) -> Vec<f32> {\n\tlet cached_bark_cos_omega =\n\t\t&fl.cached_bark_cos_omega[blockflag as usize];\n\tlet mut i = 0;\n\tlet mut output = Vec::with_capacity(n as usize);\n\tlet lfv_common_term = amplitude as f32 * fl.floor0_amplitude_offset as f32 /\n\t\t((1 << fl.floor0_amplitude_bits) - 1) as f32;\n\twhile i < n as usize {\n\t\tlet cos_omega = cached_bark_cos_omega[i];\n\n\t\t// Compute p and q\n\t\tlet (p_upper_border, q_upper_border) =\n\t\tif fl.floor0_order & 1 == 1 {\n\t\t\t((fl.floor0_order as usize - 3) / 2,\n\t\t\t\t(fl.floor0_order as usize - 1) / 2)\n\t\t} else {\n\t\t\tlet v = (fl.floor0_order as usize - 2) / 2;\n\t\t\t(v, v)\n\t\t};\n\t\tlet (mut p, mut q) =\n\t\tif fl.floor0_order & 1 == 1 {\n\t\t\t(1.0 - cos_omega * cos_omega, 0.25)\n\t\t} else {\n\t\t\t((1.0 - cos_omega) / 2.0, (1.0 + cos_omega) / 2.0)\n\t\t};\n\t\tfor j in 0 .. p_upper_border + 1 {\n\t\t\tlet pm = cos_coefficients[2 * j + 1] - cos_omega;\n\t\t\tp *= 4.0 * pm * pm;\n\t\t}\n\t\tfor j in 0 .. q_upper_border + 1 {\n\t\t\tlet qm = cos_coefficients[2 * j] - cos_omega;\n\t\t\tq *= 4.0 * qm * qm;\n\t\t}\n\n\t\t// Compute linear_floor_value\n\t\tlet linear_floor_value = (0.11512925 *\n\t\t\t(lfv_common_term / (p+q).sqrt() - fl.floor0_amplitude_offset as f32)\n\t\t).exp();\n\n\t\t// Write into output\n\t\tlet mut iteration_condition = cos_omega;\n\t\twhile cos_omega == iteration_condition {\n\t\t\toutput.push(linear_floor_value);\n\t\t\ti += 1;\n\t\t\titeration_condition = match cached_bark_cos_omega.get(i) {\n\t\t\t\tSome(v) => *v,\n\t\t\t\tNone => break,\n\t\t\t};\n\t\t}\n\t}\n\treturn output;\n}\n\n// Returns Err if the floor is \"unused\"\nfn floor_one_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],\n\t\tfl :&FloorTypeOne) -> Result<Vec<u32>, FloorSpecialCase> {\n\t// TODO perhaps it means invalid audio packet if reading the nonzero\n\t// flag doesn't succeed bc end of packet. Perhaps it does not.\n\tif !try!(rdr.read_bit_flag()) {\n\t\ttry!(Err(()));\n\t}\n\tlet mut floor1_y = Vec::new();\n\tlet v = &[256, 128, 86, 64];\n\tlet range = v[(fl.floor1_multiplier - 1) as usize];\n\tlet b = ::ilog(range - 1);\n\tfloor1_y.push(try!(rdr.read_dyn_u8(b)) as u32);\n\tfloor1_y.push(try!(rdr.read_dyn_u8(b)) as u32);\n\n\tfor class in &fl.floor1_partition_class {\n\t\tlet uclass = *class as usize;\n\t\tlet cdim = fl.floor1_class_dimensions[uclass];\n\t\tlet cbits = fl.floor1_class_subclasses[uclass];\n\t\tlet csub = (1 << cbits) - 1;\n\t\tlet mut cval = 0;\n\t\tif cbits > 0 {\n\t\t\tlet cbook = fl.floor1_class_masterbooks[uclass] as usize;\n\t\t\tcval = try!(rdr.read_huffman(&codebooks[cbook].codebook_huffman_tree));\n\t\t}\n\t\tfor _ in 0 .. cdim {\n\t\t\tlet book = fl.floor1_subclass_books[uclass][(cval & csub) as usize];\n\t\t\tcval >>= cbits;\n\t\t\tif book >= 0 {\n\t\t\t\tlet tree = &codebooks[book as usize].codebook_huffman_tree;\n\t\t\t\tfloor1_y.push(try!(rdr.read_huffman(tree)));\n\t\t\t} else {\n\t\t\t\tfloor1_y.push(0);\n\t\t\t}\n\t\t}\n\t}\n\treturn Ok(floor1_y);\n}\n\nfn extr_neighbor<F>(v :&[u32], max_idx :usize,\n\t\tcompare :F, relation :&str) -> (usize, u32)\n\t\twhere F :Fn(u32, u32) -> std::cmp::Ordering {\n\tuse std::cmp::Ordering;\n\n\tlet bound = v[max_idx];\n\tlet prefix = &v[..max_idx];\n\tlet smaller = |a, b| compare(a, b) == Ordering::Less;\n\n\t// First find a first index that fulfills\n\t// the criterion of being \"smaller\" than bound\n\tlet min_idx = prefix.iter()\n\t\t.position(|&val| smaller(val, bound))\n\t\t.unwrap_or_else(||\n\t\t\tpanic!(\"No index y < {0} found where v[y] is {1} than v[{0}] = 0x{2:08x}!\",\n\t\t\t\tmax_idx, relation, bound));\n\n\t// Now search for \"bigger\" entries\n\tlet (offset, max_neighbor) = prefix[min_idx..].iter().cloned()\n\t\t.enumerate()\n\t\t// According to documentation of Iterator::max_by,\n\t\t// \"If several elements are equally maximum, the last element is returned\".\n\t\t// Thus, in order to find the *first* maximum element,\n\t\t// we need to search from the end of `prefix`\n\t\t.rev()\n\t\t.filter(|&(_i, val)| smaller(val, bound))\n\t\t.max_by(|&(_, a), &(_, b)| compare(a, b))\n\t\t.unwrap_or((0, v[min_idx]));\n\n\t(min_idx + offset, max_neighbor)\n}\n\nfn low_neighbor(v :&[u32], x :usize) -> (usize, u32) {\n\textr_neighbor(v, x, |a, b| a.cmp(&b), \"smaller\")\n}\n\n\nfn high_neighbor(v :&[u32], x :usize) -> (usize, u32) {\n\textr_neighbor(v, x, |a, b| b.cmp(&a), \"bigger\")\n}\n\n#[test]\nfn test_low_neighbor() {\n\tlet v = [1, 4, 2, 3, 6, 5];\n\t// 0 will panic\n\tassert_eq!(low_neighbor(&v, 1), (0, 1));\n\tassert_eq!(low_neighbor(&v, 2), (0, 1));\n\tassert_eq!(low_neighbor(&v, 3), (2, 2));\n\tassert_eq!(low_neighbor(&v, 4), (1, 4));\n\tassert_eq!(low_neighbor(&v, 5), (1, 4));\n}\n\n\n#[test]\nfn test_high_neighbor() {\n\tlet v = [1, 4, 2, 3, 6, 5];\n\t// 0, 1 will panic\n\tassert_eq!(high_neighbor(&v, 2), (1, 4));\n\tassert_eq!(high_neighbor(&v, 3), (1, 4));\n\t// 4 will panic\n\tassert_eq!(high_neighbor(&v, 5), (4, 6));\n}\n\n#[test]\nfn test_high_neighbor_ex() {\n\t// Data extracted from example file\n\tlet v = [0, 128, 12, 46, 4, 8, 16, 23,\n\t\t33, 70, 2, 6, 10, 14, 19, 28, 39, 58, 90];\n\n\t// 0, 1 will panic\n\tassert_eq!(high_neighbor(&v, 2), (1, 128));\n\tassert_eq!(high_neighbor(&v, 3), (1, 128));\n\tassert_eq!(high_neighbor(&v, 4), (2, 12));\n\tassert_eq!(high_neighbor(&v, 5), (2, 12));\n\tassert_eq!(high_neighbor(&v, 6), (3, 46));\n\tassert_eq!(high_neighbor(&v, 7), (3, 46));\n\tassert_eq!(high_neighbor(&v, 8), (3, 46));\n\tassert_eq!(high_neighbor(&v, 9), (1, 128));\n\tassert_eq!(high_neighbor(&v, 10), (4, 4));\n\tassert_eq!(high_neighbor(&v, 11), (5, 8));\n\tassert_eq!(high_neighbor(&v, 12), (2, 12));\n\tassert_eq!(high_neighbor(&v, 13), (6, 16));\n\tassert_eq!(high_neighbor(&v, 14), (7, 23));\n\tassert_eq!(high_neighbor(&v, 15), (8, 33));\n\tassert_eq!(high_neighbor(&v, 16), (3, 46));\n\tassert_eq!(high_neighbor(&v, 17), (9, 70));\n\tassert_eq!(high_neighbor(&v, 18), (1, 128));\n}\n\n#[test]\n#[should_panic]\nfn test_high_neighbor_panic() {\n\thigh_neighbor(&[1, 4, 3, 2, 6, 5], 4);\n}\n\n#[test]\n#[should_panic]\nfn test_low_neighbor_panic() {\n\tlow_neighbor(&[2, 4, 3, 1, 6, 5], 3);\n}\n\nfn render_point(x0 :u32, y0 :u32, x1 :u32, y1 :u32, x :u32) -> u32 {\n\t// TODO find out whether the type choices in this method are okay\n\t// (esp. the i32 choice).\n\tlet dy = y1 as i32 - y0 as i32;\n\tlet adx = x1 - x0;\n\tlet ady = dy.abs() as u32;\n\tlet err = ady * (x - x0);\n\tlet off = err / adx;\n\tif dy < 0 {\n\t\treturn y0 - off;\n\t} else {\n\t\treturn y0 + off;\n\t}\n}\n\n#[test]\nfn test_render_point() {\n\t// Test data taken from real life ogg/vorbis file.\n\tassert_eq!(render_point(0, 28, 128, 67, 12), 31);\n\tassert_eq!(render_point(12, 38, 128, 67, 46), 46);\n\tassert_eq!(render_point(0, 28, 12, 38, 4), 31);\n\tassert_eq!(render_point(4, 33, 12, 38, 8), 35);\n\tassert_eq!(render_point(12, 38, 46, 31, 16), 38);\n\tassert_eq!(render_point(16, 30, 46, 31, 23), 30);\n\tassert_eq!(render_point(23, 40, 46, 31, 33), 37);\n\tassert_eq!(render_point(46, 31, 128, 67, 70), 41);\n\tassert_eq!(render_point(0, 28, 4, 33, 2), 30);\n\tassert_eq!(render_point(4, 33, 8, 43, 6), 38);\n\tassert_eq!(render_point(8, 43, 12, 38, 10), 41);\n\tassert_eq!(render_point(12, 38, 16, 30, 14), 34);\n\tassert_eq!(render_point(16, 30, 23, 40, 19), 34);\n\tassert_eq!(render_point(23, 40, 33, 26, 28), 33);\n\tassert_eq!(render_point(33, 26, 46, 31, 39), 28);\n\tassert_eq!(render_point(46, 31, 70, 20, 58), 26);\n\tassert_eq!(render_point(70, 20, 128, 67, 90), 36);\n}\n\nfn floor_one_curve_compute_amplitude(floor1_y :&[u32], fl :&FloorTypeOne) -> (Vec<u32>, Vec<bool>) {\n\tlet v = &[256, 128, 86, 64];\n\tlet range = v[(fl.floor1_multiplier - 1) as usize] as i32;\n\tlet mut floor1_step2_flag = Vec::new();\n\tfloor1_step2_flag.push(true);\n\tfloor1_step2_flag.push(true);\n\tlet mut floor1_final_y = Vec::new();\n\tfloor1_final_y.push(floor1_y[0]);\n\tfloor1_final_y.push(floor1_y[1]);\n\n\tfor (i, el) in fl.floor1_x_list.iter().enumerate().skip(2) {\n\t\tlet cur_low_neighbor = low_neighbor(&fl.floor1_x_list, i);\n\t\tlet cur_high_neighbor = high_neighbor(&fl.floor1_x_list, i);\n\t\tlet predicted = render_point(\n\t\t\tcur_low_neighbor.1, floor1_final_y[cur_low_neighbor.0],\n\t\t\tcur_high_neighbor.1, floor1_final_y[cur_high_neighbor.0], *el) as i32;\n\t\tlet val = floor1_y[i] as i32;\n\t\tlet highroom = range - predicted;\n\t\tlet lowroom = predicted;\n\t\tlet room = min(highroom, lowroom) * 2;\n\t\tif val > 0 {\n\t\t\tfloor1_step2_flag[cur_low_neighbor.0] = true;\n\t\t\tfloor1_step2_flag[cur_high_neighbor.0] = true;\n\t\t\tfloor1_step2_flag.push(true);\n\t\t\tfloor1_final_y.push(if val >= room {\n\t\t\t\tif highroom > lowroom {\n\t\t\t\t\tpredicted + val - lowroom\n\t\t\t\t} else {\n\t\t\t\t\tpredicted - val + highroom - 1\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tpredicted + (if val % 2 == 1 {\n\t\t\t\t\t- val - 1 } else { val } >> 1)\n\t\t\t} as u32);\n\t\t} else {\n\t\t\tfloor1_final_y.push(predicted as u32);\n\t\t\tfloor1_step2_flag.push(false);\n\t\t}\n\t}\n\t// Clamp all entries of floor1_final_y to range\n\tfor el in &mut floor1_final_y {\n\t\t*el = min(range as u32 - 1, *el);\n\t}\n\treturn (floor1_final_y, floor1_step2_flag);\n}\n\nstatic FLOOR1_INVERSE_DB_TABLE :&[f32] = &[\n\t1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07,\n\t1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07,\n\t1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.1287530e-07,\n\t2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07,\n\t2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07,\n\t3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07,\n\t4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07,\n\t6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07,\n\t7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07,\n\t1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06,\n\t1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06,\n\t1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06,\n\t2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06,\n\t2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06,\n\t3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06,\n\t4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06,\n\t5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06,\n\t7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06,\n\t9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05,\n\t1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05,\n\t1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05,\n\t2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05,\n\t2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05,\n\t3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05,\n\t4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05,\n\t5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05,\n\t7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05,\n\t9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824,\n\t0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085,\n\t0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536,\n\t0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449,\n\t0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787,\n\t0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456,\n\t0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927,\n\t0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058,\n\t0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457,\n\t0.00092223983, 0.00098217216, 0.0010459992,  0.0011139742,\n\t0.0011863665,  0.0012634633,  0.0013455702,  0.0014330129,\n\t0.0015261382,  0.0016253153,  0.0017309374,  0.0018434235,\n\t0.0019632195,  0.0020908006,  0.0022266726,  0.0023713743,\n\t0.0025254795,  0.0026895994,  0.0028643847,  0.0030505286,\n\t0.0032487691,  0.0034598925,  0.0036847358,  0.0039241906,\n\t0.0041792066,  0.0044507950,  0.0047400328,  0.0050480668,\n\t0.0053761186,  0.0057254891,  0.0060975636,  0.0064938176,\n\t0.0069158225,  0.0073652516,  0.0078438871,  0.0083536271,\n\t0.0088964928,  0.009474637,   0.010090352,   0.010746080,\n\t0.011444421,   0.012188144,   0.012980198,   0.013823725,\n\t0.014722068,   0.015678791,   0.016697687,   0.017782797,\n\t0.018938423,   0.020169149,   0.021479854,   0.022875735,\n\t0.024362330,   0.025945531,   0.027631618,   0.029427276,\n\t0.031339626,   0.033376252,   0.035545228,   0.037855157,\n\t0.040315199,   0.042935108,   0.045725273,   0.048696758,\n\t0.051861348,   0.055231591,   0.058820850,   0.062643361,\n\t0.066714279,   0.071049749,   0.075666962,   0.080584227,\n\t0.085821044,   0.091398179,   0.097337747,   0.10366330,\n\t0.11039993,    0.11757434,    0.12521498,    0.13335215,\n\t0.14201813,    0.15124727,    0.16107617,    0.17154380,\n\t0.18269168,    0.19456402,    0.20720788,    0.22067342,\n\t0.23501402,    0.25028656,    0.26655159,    0.28387361,\n\t0.30232132,    0.32196786,    0.34289114,    0.36517414,\n\t0.38890521,    0.41417847,    0.44109412,    0.46975890,\n\t0.50028648,    0.53279791,    0.56742212,    0.60429640,\n\t0.64356699,    0.68538959,    0.72993007,    0.77736504,\n\t0.82788260,    0.88168307,    0.9389798,     1.];\n\nfn render_line(x0 :u32, y0 :u32, x1 :u32, y1 :u32, v :&mut Vec<u32>) {\n\t// TODO find out whether the type choices in this method are okay\n\tlet dy = y1 as i32 - y0 as i32;\n\tlet adx = x1 as i32 - x0 as i32;\n\tlet ady = dy.abs();\n\tlet base = dy / adx;\n\tlet mut y = y0 as i32;\n\tlet mut err = 0;\n\tlet sy = base + (if dy < 0 { -1 } else { 1 });\n\tlet ady = ady  - base.abs() * adx;\n\tv.push(y as u32);\n\tfor _ in (x0 + 1) .. x1 {\n\t\terr += ady;\n\t\tif err >= adx {\n\t\t\terr -= adx;\n\t\t\ty += sy;\n\t\t} else {\n\t\t\ty += base;\n\t\t}\n\t\tv.push(y as u32);\n\t}\n}\n\nfn floor_one_curve_synthesis(floor1_final_y :Vec<u32>,\n\t\tfloor1_step2_flag :Vec<bool>, fl :&FloorTypeOne, n :u16) -> Vec<f32> {\n\tlet floor1_final_y_s = |i :usize| { floor1_final_y[fl.floor1_x_list_sorted[i].0] };\n\tlet floor1_x_list_s = |i :usize| { fl.floor1_x_list_sorted[i].1 };\n\tlet floor1_step2_flag_s = |i :usize| {\n\t\tfloor1_step2_flag[fl.floor1_x_list_sorted[i].0] };\n\tlet mut hx = 0;\n\tlet mut lx = 0;\n\tlet mut hy = 0;\n\tlet mut floor = Vec::with_capacity(n as usize);\n\tlet mut ly = floor1_final_y_s(0) * fl.floor1_multiplier as u32;\n\tfor i in 1 .. fl.floor1_x_list.len() {\n\t\tif floor1_step2_flag_s(i) {\n\t\t\thy = floor1_final_y_s(i) * fl.floor1_multiplier as u32;\n\t\t\thx = floor1_x_list_s(i);\n\t\t\trender_line(lx, ly, hx, hy, &mut floor);\n\t\t\tlx = hx;\n\t\t\tly = hy;\n\t\t}\n\t}\n\tif hx < n as u32 {\n\t\trender_line(hx, hy, n as u32, hy, &mut floor);\n\t} else if hx > n as u32 {\n\t\tfloor.truncate(n as usize);\n\t}\n\n\tfloor.into_iter()\n\t\t.map(|idx| FLOOR1_INVERSE_DB_TABLE[idx as usize])\n\t\t.collect()\n}\n\nfn floor_decode<'a>(rdr :&mut BitpackCursor,\n\t\tident :&IdentHeader, mapping :&Mapping, codebooks :&[Codebook],\n\t\tfloors :&'a [Floor]) -> Result<Vec<DecodedFloor<'a>>, ()> {\n\tlet mut decoded_floor_infos = Vec::with_capacity(ident.audio_channels as usize);\n\tfor i in 0 .. ident.audio_channels as usize {\n\t\tlet submap_number = mapping.mapping_mux[i] as usize;\n\t\tlet floor_number = mapping.mapping_submap_floors[submap_number];\n\t\tlet floor = &floors[floor_number as usize];\n\t\tuse self::FloorSpecialCase::*;\n\t\tlet floor_res = match floor {\n\t\t\t&Floor::TypeZero(ref fl) => {\n\t\t\t\tmatch floor_zero_decode(rdr, codebooks, fl) {\n\t\t\t\t\tOk((coeff, amp)) => DecodedFloor::TypeZero(coeff, amp, fl),\n\t\t\t\t\tErr(Unused) => DecodedFloor::Unused,\n\t\t\t\t\tErr(PacketUndecodable) => try!(Err(())),\n\t\t\t\t}\n\t\t\t},\n\t\t\t&Floor::TypeOne(ref fl) => {\n\t\t\t\tmatch floor_one_decode(rdr, codebooks, fl) {\n\t\t\t\t\tOk(dfl) => DecodedFloor::TypeOne(dfl, fl),\n\t\t\t\t\tErr(Unused) => DecodedFloor::Unused,\n\t\t\t\t\tErr(PacketUndecodable) => try!(Err(())),\n\t\t\t\t}\n\t\t\t},\n\t\t};\n\t\tdecoded_floor_infos.push(floor_res);\n\t}\n\treturn Ok(decoded_floor_infos);\n}\n\nfn residue_packet_read_partition(rdr :&mut BitpackCursor, codebook :&Codebook,\n\t\tresid :&Residue, vec_v :&mut [f32]) -> Result<(), HuffmanVqReadErr> {\n\tif resid.residue_type == 0 {\n\t\tlet codebook_dimensions = codebook.codebook_dimensions as usize;\n\t\tlet step = resid.residue_partition_size as usize / codebook_dimensions;\n\t\tfor i in 0 .. step {\n\t\t\tlet entry_temp = try!(rdr.read_huffman_vq(codebook));\n\t\t\tfor (j, e) in entry_temp.iter().enumerate() {\n\t\t\t\tvec_v[i + j * step] += *e;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// Common for both format 1 and 2\n\t\tlet partition_size = resid.residue_partition_size as usize;\n\t\tlet mut i = 0;\n\t\twhile i < partition_size {\n\t\t\tlet entries = try!(rdr.read_huffman_vq(codebook));\n\t\t\tlet vs = if let Some(vs) = vec_v.get_mut(i..(i + entries.len())) {\n\t\t\t\tvs\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t};\n\n\t\t\tfor (v, e) in vs.iter_mut().zip(entries.iter()) {\n\t\t\t\t*v += *e;\n\t\t\t}\n\n\t\t\ti += entries.len();\n\t\t}\n\t}\n\tOk(())\n}\n\nfn residue_packet_decode_inner(rdr :&mut BitpackCursor, cur_blocksize :u16,\n\t\tdo_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result<Vec<f32>, ()> {\n\n\tlet ch = do_not_decode_flag.len();\n\tlet actual_size = (cur_blocksize / 2) as usize;\n\n\t// Older versions of the spec say max() here,\n\t// but there's been a bug in the spec.\n\t// It's been fixed since:\n\t// https://github.com/xiph/vorbis/pull/35\n\tlet limit_residue_begin = min(resid.residue_begin as usize, actual_size);\n\tlet limit_residue_end = min(resid.residue_end as usize, actual_size);\n\n\tlet cur_codebook = &codebooks[resid.residue_classbook as usize];\n\tlet classwords_per_codeword = cur_codebook.codebook_dimensions as usize;\n\tlet n_to_read = limit_residue_end - limit_residue_begin;\n\tlet partitions_to_read = n_to_read / resid.residue_partition_size as usize;\n\tlet residue_classbok_ht = &cur_codebook.codebook_huffman_tree;\n\n\t// Allocate and zero all vectors that will be returned\n\tlet mut vectors = vec![0.; ch * actual_size];\n\n\tif n_to_read == 0 {\n\t\t// No residue to decode\n\t\treturn Ok(vectors);\n\t}\n\n\tif classwords_per_codeword == 0 {\n\t\t// A value of 0 would create an infinite loop.\n\t\t// Therefore, throw an error in this case.\n\t\ttry!(Err(()));\n\t}\n\n\t'pseudo_return: loop {\n\t\t// ENdofpacketisnOrmal macro. Local replacement for try.\n\t\tmacro_rules! eno {\n\t\t\t($expr:expr) => (match $expr {\n\t\t\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t\t\t$crate::std::result::Result::Err(_) => break 'pseudo_return,\n\t\t\t})\n\t\t}\n\t\tlet cl_stride :usize = partitions_to_read + classwords_per_codeword;\n\t\tlet mut classifications = vec![0; ch as usize * cl_stride];\n\t\tfor pass in 0 .. 8 {\n\t\t\tlet mut partition_count = 0;\n\t\t\twhile partition_count < partitions_to_read {\n\t\t\t\tif pass == 0 {\n\t\t\t\t\tfor (j, do_not_decode) in do_not_decode_flag.iter().enumerate() {\n\t\t\t\t\t\tif *do_not_decode {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet mut temp = eno!(rdr.read_huffman(residue_classbok_ht));\n\t\t\t\t\t\tfor i in (0 .. classwords_per_codeword).rev() {\n\t\t\t\t\t\t\tclassifications[j * cl_stride + i + partition_count] =\n\t\t\t\t\t\t\ttemp % resid.residue_classifications as u32;\n\t\t\t\t\t\t\ttemp = temp / resid.residue_classifications as u32;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor _ in 0 .. classwords_per_codeword {\n\t\t\t\t\tif partition_count >= partitions_to_read {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfor (j, do_not_decode) in do_not_decode_flag.iter().enumerate() {\n\t\t\t\t\t\tif *do_not_decode {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlet offs = limit_residue_begin + partition_count * resid.residue_partition_size as usize;\n\t\t\t\t\t\tlet vec_j_offs = &mut vectors[(j * actual_size + offs) .. ((j + 1) * actual_size)];\n\t\t\t\t\t\tlet vqclass = classifications[j * cl_stride + partition_count] as usize;\n\t\t\t\t\t\tlet vqbook_opt = resid.residue_books[vqclass].get_val(pass);\n\t\t\t\t\t\tif let Some(vqbook) = vqbook_opt {\n\t\t\t\t\t\t\tlet codebook = &codebooks[vqbook as usize];\n\t\t\t\t\t\t\t// codebook is checked by header decode to have a value mapping\n\t\t\t\t\t\t\t// Decode the partition into output vector number j (vec_j).\n\t\t\t\t\t\t\tmatch residue_packet_read_partition(rdr,\n\t\t\t\t\t\t\t\t\tcodebook, resid, vec_j_offs) {\n\t\t\t\t\t\t\t\tOk(_) => (),\n\t\t\t\t\t\t\t\tErr(err) => {\n\t\t\t\t\t\t\t\t\tuse ::header::HuffmanVqReadErr::*;\n\t\t\t\t\t\t\t\t\tmatch err {\n\t\t\t\t\t\t\t\t\t\tEndOfPacket => break 'pseudo_return,\n\t\t\t\t\t\t\t\t\t\tNoVqLookupForCodebook =>\n\t\t\t\t\t\t\t\t\t\t\tpanic!(\"Codebook must have a value mapping\"),\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tpartition_count += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tbreak;\n\t}\n\n\treturn Ok(vectors);\n}\n\n\n// Ok means \"fine\" (or end of packet, but thats \"fine\" too!),\n// Err means \"not fine\" -- the whole packet must be discarded\nfn residue_packet_decode(rdr :&mut BitpackCursor, cur_blocksize :u16,\n\t\tdo_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result<Vec<f32>, ()> {\n\n\tlet ch = do_not_decode_flag.len();\n\tlet vec_size = (cur_blocksize / 2) as usize;\n\n\tif resid.residue_type == 2 {\n\t\tlet mut to_decode_found = false;\n\t\tfor do_not_decode in do_not_decode_flag {\n\t\t\tif !do_not_decode {\n\t\t\t\tto_decode_found = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif !to_decode_found {\n\t\t\t// Don't attempt to decode, but return vectors,\n\t\t\t// as required per spec only residue 2 has this.\n\t\t\treturn Ok(vec![0.; ch * vec_size]);\n\t\t} else {\n\t\t\t// Construct a do_not_decode flag array\n\t\t\tlet c_do_not_decode_flag = [false];\n\n\t\t\tlet vectors = try!(residue_packet_decode_inner(rdr,\n\t\t\t\tcur_blocksize * ch as u16, &c_do_not_decode_flag,\n\t\t\t\tresid, codebooks));\n\n\t\t\t// Post decode step\n\t\t\tlet mut vectors_deinterleaved = Vec::with_capacity(ch * vec_size);\n\t\t\tfor j in 0 .. ch {\n\t\t\t\tlet iter = vectors.chunks(ch).map(|chunk| chunk[j]);\n\t\t\t\tvectors_deinterleaved.extend(iter);\n\t\t\t}\n\t\t\treturn Ok(vectors_deinterleaved);\n\t\t}\n\t} else {\n\t\treturn residue_packet_decode_inner(rdr, cur_blocksize,\n\t\t\tdo_not_decode_flag, resid, codebooks);\n\t}\n}\n\n#[inline]\nfn inverse_couple(m :f32, a :f32) -> (f32, f32) {\n\tif m > 0. {\n\t\tif a > 0. {\n\t\t\t(m, m - a)\n\t\t} else {\n\t\t\t(m + a, m)\n\t\t}\n\t} else {\n\t\tif a > 0. {\n\t\t\t(m, m + a)\n\t\t} else {\n\t\t\t(m - a, m)\n\t\t}\n\t}\n}\n\n// TODO this is probably slower than a replacement of\n// this function in unsafe code, no idea\nfn dual_mut_idx<T>(v :&mut [T], idx_a :usize, idx_b :usize)\n\t\t-> (&mut T, &mut T) {\n\tassert_ne!(idx_a, idx_b, \"not allowed, indices must be different!\");\n\n\tlet range = if idx_a < idx_b { idx_a..idx_b+1 } else { idx_b..idx_a+1 };\n\tlet segment = &mut v[range];\n\tlet (first, rest) = segment.split_first_mut().unwrap();\n\tlet (last, _) = rest.split_last_mut().unwrap();\n\t(first, last)\n}\n\nfn dct_iv_slow(buffer :&mut [f32]) {\n\tlet x = buffer.to_vec();\n\tlet n = buffer.len();\n\tlet nmask = (n << 3) - 1;\n\tlet mcos = (0 .. 8 * n)\n\t\t.map(|i| (std::f32::consts::FRAC_PI_4 * (i as f32) / (n as f32)).cos())\n\t\t.collect::<Vec<_>>();\n\tfor i in 0 .. n {\n\t\tlet mut acc = 0.;\n\t\tfor j in 0 .. n {\n\t\t\tacc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask];\n\t\t}\n\t\tbuffer[i] = acc;\n\t}\n}\n\n#[allow(dead_code)]\nfn inverse_mdct_slow(buffer :&mut [f32]) {\n\tlet n = buffer.len();\n\tlet n4 = n >> 2;\n\tlet n2 = n >> 1;\n\tlet n3_4 = n - n4;\n\tlet mut temp = buffer[0 .. n2].to_vec();\n\tdct_iv_slow(&mut temp); // returns -c'-d, a-b'\n\tfor i in 0 .. n4 {\n\t\tbuffer[i] = temp[i + n4]; // a-b'\n\t}\n\tfor i in n4 .. n3_4 {\n\t\tbuffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d'\n\t}\n\tfor i in n3_4 .. n {\n\t\tbuffer[i] = -temp[i - n3_4]; // c'+d\n\t}\n}\n\n#[cfg(test)]\n#[test]\nfn test_imdct_slow() {\n\tuse imdct_test::*;\n\tlet mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1);\n\tinverse_mdct_slow(&mut arr_1);\n\tlet mismatches = fuzzy_compare_array(\n\t\t&arr_1, &IMDCT_OUTPUT_TEST_ARR_1,\n\t\t0.00005, true);\n\tlet mismatches_limit = 0;\n\tif mismatches > mismatches_limit {\n\t\tpanic!(\"Numer of mismatches {} was larger than limit of {}\",\n\t\t\tmismatches, mismatches_limit);\n\t}\n}\n\n/// The right part of the previous window\n///\n/// This is the only state that needs to be changed\n/// once the headers are read.\n#[derive(Clone)]\npub struct PreviousWindowRight {\n\tdata :Option<Vec<Vec<f32>>>,\n}\n\nimpl PreviousWindowRight {\n\t/// Initialisation for new streams\n\tpub fn new() -> Self {\n\t\treturn PreviousWindowRight{ data : None };\n\t}\n\t/// If the state is still uninitialized\n\tpub fn is_empty(&self) -> bool {\n\t\tself.data.is_none()\n\t}\n}\n\n/**\nReturns the per-channel sample count of a packet if it were decoded.\n\nThis operation is very cheap and doesn't involve actual decoding of the packet.\n\nNote: for the first packet in a stream, or in other instances when\nthe `PreviousWindowRight` is reset, the decoding functions will return\n0 samples for that packet, while this function returns a different number.\nPlease use the `PreviousWindowRight::is_empty` function or other methods\nto check for this case.\n*/\npub fn get_decoded_sample_count(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8])\n\t\t-> Result<usize, AudioReadError> {\n\tlet mut rdr = BitpackCursor::new(packet);\n\tif try!(rdr.read_bit_flag()) {\n\t\ttry!(Err(AudioReadError::AudioIsHeader));\n\t}\n\tlet mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1)));\n\tlet mode = &setup.modes[mode_number as usize];\n\tlet bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 };\n\tlet n :u16 = 1 << bs;\n\tlet previous_next_window_flag = if mode.mode_blockflag {\n\t\tSome((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag())))\n\t} else {\n\t\tNone\n\t};\n\t// Compute windowing info for left window\n\tlet window_center = n >> 1;\n\tlet (left_win_start, _left_win_end, _left_n, _left_n_use_bs1) =\n\t\tif previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) {\n\t\t\t(0, window_center, n >> 1, mode.mode_blockflag)\n\t\t} else {\n\t\t\tlet bs_0_exp = 1 << ident.blocksize_0;\n\t\t\t((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false)\n\t\t};\n\n\t// Compute windowing info for right window\n\tlet (right_win_start, _right_win_end) =\n\t\tif previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) {\n\t\t\t(window_center, n)\n\t\t} else {\n\t\t\tlet bs_0_exp = 1 << ident.blocksize_0;\n\t\t\t((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2)\n\t\t};\n\n\tOk((right_win_start - left_win_start) as usize)\n}\n\n/**\nMain audio packet decoding function\n\nPass your info to this function to get your raw packet data decoded.\n\nPanics if the passed PreviousWindowRight struct doesn't match the info\nfrom the ident header.\n*/\npub fn read_audio_packet_generic<S :Samples>(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight)\n\t\t-> Result<S, AudioReadError> {\n\tlet mut rdr = BitpackCursor::new(packet);\n\tif try!(rdr.read_bit_flag()) {\n\t\ttry!(Err(AudioReadError::AudioIsHeader));\n\t}\n\tlet mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1)));\n\tlet mode = if let Some(mode) = setup.modes.get(mode_number as usize) {\n\t\tmode\n\t} else {\n\t\ttry!(Err(AudioReadError::AudioBadFormat))\n\t};\n\tlet mapping = &setup.mappings[mode.mode_mapping as usize];\n\tlet bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 };\n\tlet n :u16 = 1 << bs;\n\tlet previous_next_window_flag = if mode.mode_blockflag {\n\t\tSome((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag())))\n\t} else {\n\t\tNone\n\t};\n\t// Decode the floors\n\tlet decoded_floor_infos = try!(floor_decode(&mut rdr, ident, mapping,\n\t\t&setup.codebooks, &setup.floors));\n\n\t// Now calculate the no_residue vector\n\tlet mut no_residue = TinyVec::<[bool; 32]>::new();\n\tfor fl in &decoded_floor_infos {\n\t\tno_residue.push(fl.is_unused());\n\t}\n\t// and also propagate\n\tfor (&mag, &angle) in\n\t\t\tmapping.mapping_magnitudes.iter().zip(mapping.mapping_angles.iter()) {\n\t\tif ! (no_residue[mag as usize] && no_residue[angle as usize]) {\n\t\t\tno_residue[mag as usize] = false;\n\t\t\tno_residue[angle as usize] = false;\n\t\t}\n\t}\n\n\t// Residue decode.\n\tlet mut residue_vectors = vec![vec![]; mapping.mapping_mux.len()];\n\t// Helper variable\n\tlet resid_vec_len = (n / 2) as usize;\n\tfor (i, &residue_number) in mapping.mapping_submap_residues.iter().enumerate() {\n\t\tlet mut do_not_decode_flag = TinyVec::<[bool; 32]>::new();\n\t\tfor (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() {\n\t\t\tif mapping_mux_j as usize == i {\n\t\t\t\tdo_not_decode_flag.push(no_residue[j]);\n\t\t\t}\n\t\t}\n\t\tlet cur_residue = &setup.residues[residue_number as usize];\n\t\tlet vectors = match residue_packet_decode(&mut rdr, n,\n\t\t\t\t&do_not_decode_flag, cur_residue, &setup.codebooks) {\n\t\t\tOk(v) => v,\n\t\t\tErr(_) => return Err(AudioReadError::AudioBadFormat),\n\t\t};\n\t\t// The vectors Vec<f32> now contains the do_not_decode_flag.len()\n\t\t// many decoded residue vectors, each vector occupying n/2 scalars.\n\t\tlet mut ch = 0;\n\t\tfor (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() {\n\t\t\tif mapping_mux_j as usize == i {\n\t\t\t\t// TODO get rid of this copy somehow...\n\t\t\t\tlet vec_at_ch = &vectors[resid_vec_len * ch .. resid_vec_len * (ch + 1)];\n\t\t\t\tresidue_vectors[j].clear();\n\t\t\t\tresidue_vectors[j].extend_from_slice(vec_at_ch);\n\t\t\t\tch += 1;\n\t\t\t}\n\t\t}\n\t}\n\n\trecord_residue_pre_inverse!(residue_vectors);\n\n\t// Inverse coupling\n\tfor (&mag, &angle) in\n\t\t\tmapping.mapping_magnitudes.iter().rev().zip(mapping.mapping_angles.iter().rev()) {\n\t\tlet (mag_vector, angle_vector) = dual_mut_idx(&mut residue_vectors,\n\t\t\tmag as usize, angle as usize);\n\t\tfor (m, a) in mag_vector.iter_mut().zip(angle_vector.iter_mut()) {\n\t\t\t// https://github.com/rust-lang/rfcs/issues/372\n\t\t\t// grumble grumble...\n\t\t\tlet (new_m, new_a) = inverse_couple(*m, *a);\n\t\t\t*m = new_m;\n\t\t\t*a = new_a;\n\t\t}\n\t}\n\n\trecord_residue_post_inverse!(residue_vectors);\n\n\t// Dot product\n\tlet mut audio_spectri = Vec::with_capacity(ident.audio_channels as usize);\n\tfor (residue_vector, chan_decoded_floor) in\n\t\t\tresidue_vectors.iter().zip(decoded_floor_infos.iter()) {\n\t\tlet mut floor_decoded :Vec<f32> = match chan_decoded_floor {\n\t\t\t&DecodedFloor::TypeZero(ref coefficients, amplitude, ref fl) => {\n\t\t\t\tfloor_zero_compute_curve(coefficients, amplitude,\n\t\t\t\t\tfl, mode.mode_blockflag, n / 2)\n\t\t\t},\n\t\t\t&DecodedFloor::TypeOne(ref floor_y, ref fl) => {\n\t\t\t\tlet (floor1_final_y, floor1_step2_flag) =\n\t\t\t\t\tfloor_one_curve_compute_amplitude(floor_y, fl);\n\t\t\t\tfloor_one_curve_synthesis(floor1_final_y,\n\t\t\t\t\tfloor1_step2_flag, fl, n / 2)\n\t\t\t},\n\t\t\t&DecodedFloor::Unused => {\n\t\t\t\t// Generate zero'd floor of length n/2\n\t\t\t\tvec![0.; (n / 2) as usize]\n\t\t\t},\n\t\t};\n\n\t\t// The only legal length is n/2.\n\t\t// The implementation should ensure this,\n\t\t// but its good for debugging to have this\n\t\t// confirmed.\n\t\tdebug_assert_eq!(residue_vector.len(), (n / 2) as usize);\n\t\tdebug_assert_eq!(floor_decoded.len(), (n / 2) as usize);\n\n\t\t// Now do the multiplication\n\t\tfor (fl_sc, r_sc) in floor_decoded.iter_mut().zip(residue_vector.iter()) {\n\t\t\t*fl_sc *= *r_sc;\n\t\t}\n\t\taudio_spectri.push(floor_decoded);\n\t}\n\n\trecord_pre_mdct!(audio_spectri);\n\n\t// Inverse MDCT\n\tfor ref mut spectrum in audio_spectri.iter_mut() {\n\t\tlet size = (n / 2) as usize;\n\t\tlet ext = iter::repeat(0.).take(size);\n\t\tspectrum.extend(ext);\n\t\tlet cached_bd = &ident.cached_bs_derived[mode.mode_blockflag as usize];\n\t\t//::imdct::inverse_mdct_naive(cached_bd, &mut spectrum[..]);\n\t\t::imdct::inverse_mdct(cached_bd, &mut spectrum[..], bs);\n\t\t//inverse_mdct_slow(&mut spectrum[..]);\n\t}\n\n\trecord_post_mdct!(audio_spectri);\n\n\t// Compute windowing info for left window\n\tlet window_center = n >> 1;\n\tlet (left_win_start, _left_win_end, _left_n, left_n_use_bs1) =\n\t\tif previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) {\n\t\t\t(0, window_center, n >> 1, mode.mode_blockflag)\n\t\t} else {\n\t\t\tlet bs_0_exp = 1 << ident.blocksize_0;\n\t\t\t((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false)\n\t\t};\n\n\t// Compute windowing info for right window\n\tlet (right_win_start, right_win_end) =\n\t\tif previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) {\n\t\t\t(window_center, n)\n\t\t} else {\n\t\t\tlet bs_0_exp = 1 << ident.blocksize_0;\n\t\t\t((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2)\n\t\t};\n\n\t/*println!(\"n={} prev_win_flag={:?} left_win_(start={}, end={}, n={}) right_win(start={}, end={})\",\n\t\tn, previous_next_window_flag, left_win_start, _left_win_end, _left_n,\n\t\tright_win_start, right_win_end); // */\n\n\t// Overlap add and store last half\n\t// in PreviousWindowRight\n\t// Only add if prev has elements.\n\tlet mut future_prev_halves = Vec::with_capacity(ident.audio_channels as usize);\n\tif let Some(prev_data) = pwr.data.take() {\n\t\t// TODO maybe check if prev_n matches blocksize_0 or blocksize_1,\n\t\t// and the channel number. Panic if no match of either.\n\t\tassert_eq!(audio_spectri.len(), prev_data.len());\n\n\t\tlet win_slope = &ident.cached_bs_derived[left_n_use_bs1 as usize].window_slope;\n\n\t\tfor (prev_chan, chan) in prev_data.into_iter().zip(audio_spectri.iter_mut()) {\n\t\t\tlet plen = prev_chan.len();\n\t\t\tlet left_win_start = left_win_start as usize;\n\t\t\tlet right_win_start = right_win_start as usize;\n\t\t\tlet right_win_end = right_win_end as usize;\n\n\t\t\t// Then do the actual overlap_add\n\t\t\t// Set up iterators for all the variables\n\t\t\tlet range = {\n\t\t\t\tlet start = left_win_start;\n\t\t\t\tlet end = left_win_start + plen;\n\t\t\t\tstart..end\n\t\t\t};\n\n\t\t\tlet prev = prev_chan.iter();\n\n\t\t\tlet (lhs, rhs) = {\n\t\t\t\tif win_slope.len() < plen {\n\t\t\t\t\t// According to fuzzing, code can trigger this case,\n\t\t\t\t\t// so let's error gracefully instead of panicing.\n\t\t\t\t\ttry!(Err(AudioReadError::AudioBadFormat));\n\t\t\t\t}\n\t\t\t\tlet win_slope = &win_slope[0..plen];\n\t\t\t\t(win_slope.iter(), win_slope.iter().rev())\n\t\t\t};\n\n\t\t\tfor (((v, lhs), prev), rhs) in chan[range].iter_mut().zip(lhs).zip(prev).zip(rhs) {\n\t\t\t\t*v = (*v * lhs) + (prev * rhs);\n\t\t\t}\n\n  \t\t\t// and populate the future previous half\n\t\t\tlet future_prev_half = chan[right_win_start..right_win_end].into();\n\n\t\t\tfuture_prev_halves.push(future_prev_half);\n\n\t\t\t// Remove everything left of the left window start,\n\t\t\t// by moving the the stuff right to it to the left.\n\t\t\tif left_win_start > 0 {\n\t\t\t\tfor i in 0 .. right_win_start - left_win_start {\n\t\t\t\t\tchan[i] = chan[i + left_win_start];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Now the last step: truncate the decoded packet\n\t\t\t// to cut off the right part.\n\t\t\tchan.truncate(right_win_start - left_win_start);\n\t\t\t// TODO stb_vorbis doesn't use right_win_start\n\t\t\t// in the calculation above but sth like\n\t\t\t// if len < right_win_start { len } else { right_win_start }\n\t\t}\n\t} else {\n\t\tfor chan in audio_spectri.iter_mut() {\n\t\t\tlet mut future_prev_half = Vec::with_capacity(\n\t\t\t\t(right_win_end - right_win_start) as usize);\n\t\t\tfor s in &chan[right_win_start as usize .. right_win_end as usize] {\n\t\t\t\tfuture_prev_half.push(*s);\n\t\t\t}\n\t\t\tfuture_prev_halves.push(future_prev_half);\n\t\t\t// If there is no previous window right, we have to discard\n\t\t\t// the whole packet.\n\t\t\tchan.truncate(0);\n\t\t}\n\t}\n\n\tpwr.data = Some(future_prev_halves);\n\n\t// Generate final integer samples\n\tlet final_i16_samples = S::from_floats(audio_spectri);\n\n\tOk(final_i16_samples)\n}\n\n/**\nMain audio packet decoding function\n\nPass your info to this function to get your raw packet data decoded.\n\nPanics if the passed PreviousWindowRight struct doesn't match the info\nfrom the ident header.\n*/\npub fn read_audio_packet(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight)\n\t\t-> Result<Vec<Vec<i16>>, AudioReadError> {\n\tread_audio_packet_generic(ident, setup, packet, pwr)\n}\n"
  },
  {
    "path": "src/bitpacking.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nVorbis bitpacking layer\n\nFunctionality to read content from the bitpacking layer.\n\nImplements vorbis spec, section 2.\n\nThe most important struct of this mod is the `BitpackCursor` struct.\nIt can be instantiated using `BitpackCursor::new()`.\n\nNote that this implementation doesn't fully align with the spec in the regard that it assumes a byte is an octet.\nThis is no problem on most architectures.\nThis non-alignment to the spec is due to the fact that the rust language is highly leaned towards byte == u8,\nand doesn't even have a builtin single byte type.\n*/\n\nuse huffman_tree::{VorbisHuffmanTree, PeekedDataLookupResult};\n\n/// A Cursor on slices to read numbers and bitflags, bit aligned.\npub struct BitpackCursor <'a> {\n\tbit_cursor :u8,\n\tbyte_cursor :usize,\n\tinner :&'a[u8],\n}\n\nmacro_rules! sign_extend {\n\t($num:expr, $desttype:ident, $bit_cnt_large:expr, $bit_cnt_small:expr) => {{\n\t\tlet n = $num;\n\t\tlet res :$desttype = n as $desttype;\n\t\tlet k :u8 = $bit_cnt_large - $bit_cnt_small;\n\t\tres << k >> k\n\t}};\n}\n\n#[test]\nfn test_sign_extend() {\n\tassert_eq!(sign_extend!(0b00,  i8,  8,  2),  0);\n\tassert_eq!(sign_extend!(0b01,  i8,  8,  2),  1);\n\tassert_eq!(sign_extend!(0b11,  i8,  8,  2), -1);\n\tassert_eq!(sign_extend!(0b111, i8,  8,  3), -1);\n\tassert_eq!(sign_extend!(0b101, i8,  8,  3), -3);\n\tassert_eq!(sign_extend!(0b01111110, i16, 16, 8),  126);\n\tassert_eq!(sign_extend!(0b10000010, i16, 16, 8), -126);\n}\n\n/// Returns `num` bits of 1 (but never more than 8).\nfn mask_bits(num : u8) -> u8 {\n\t!((!0u8).wrapping_shl(num as u32)) | if num >= 8 { 0xff } else { 0 }\n}\n\n// Same as mask_bits but different in a special case: for num % 8 == 0\n// Make sure that 0 <= num <= 8.\nfn bmask_bits(num : u8) -> u8 {\n\t(!0u8).wrapping_shr(8 - num as u32)\n}\n\n#[test]\nfn test_mask_bits() {\n\tassert_eq!(mask_bits(0), 0b00000000);\n\tassert_eq!(mask_bits(1), 0b00000001);\n\tassert_eq!(mask_bits(2), 0b00000011);\n\tassert_eq!(mask_bits(3), 0b00000111);\n\tassert_eq!(mask_bits(4), 0b00001111);\n\tassert_eq!(mask_bits(5), 0b00011111);\n\tassert_eq!(mask_bits(6), 0b00111111);\n\tassert_eq!(mask_bits(7), 0b01111111);\n\tassert_eq!(mask_bits(8), 0b11111111);\n}\n\n#[test]\nfn test_bmask_bits() {\n\tassert_eq!(bmask_bits(0), 0b11111111);\n\tassert_eq!(bmask_bits(1), 0b00000001);\n\tassert_eq!(bmask_bits(2), 0b00000011);\n\tassert_eq!(bmask_bits(3), 0b00000111);\n\tassert_eq!(bmask_bits(4), 0b00001111);\n\tassert_eq!(bmask_bits(5), 0b00011111);\n\tassert_eq!(bmask_bits(6), 0b00111111);\n\tassert_eq!(bmask_bits(7), 0b01111111);\n\tassert_eq!(bmask_bits(8), 0b11111111);\n}\n\n// The main macro to read bit aligned\n// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)\nmacro_rules! bpc_read_body {\n\t($rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr) => {{\n\t\tlet last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;\n\t\tlet octetnum_rounded_up :usize = last_octet_partial + $octetnum;\n\t\tlet bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;\n\n\t\tif ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {\n\t\t\t/*println!(\"Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)\",\n\t\t\t\t$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);\n\t\t\tprintln!(\"    byte_c={}; bit_c={}\", $selfarg.byte_cursor, $selfarg.bit_cursor);// */\n\t\t\t/*print!(\"Reading {} bits (byte_c={}; bit_c={}) [] = {:?}\", $bitnum,\n\t\t\t\t$selfarg.byte_cursor, $selfarg.bit_cursor,\n\t\t\t\t&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +\n\t\t\t\t1 + octetnum_rounded_up]);// */\n\t\t\tif $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() {\n\t\t\t\t//println!(\" => Out of bounds :\\\\\");\n\t\t\t\treturn Err(());\n\t\t\t}\n\t\t\tlet buf = &$selfarg.inner[$selfarg.byte_cursor\n\t\t\t\t.. $selfarg.byte_cursor + 1 + octetnum_rounded_up];\n\t\t\tlet mut res :$rettype = buf[0] as $rettype;\n\t\t\tres >>= $selfarg.bit_cursor;\n\t\t\tlet mut cur_bit_cursor = 8 - $selfarg.bit_cursor;\n\t\t\tfor i in 1 .. octetnum_rounded_up {\n\t\t\t\tres |= (buf[i] as $rettype) << cur_bit_cursor;\n\t\t\t\tcur_bit_cursor += 8;\n\t\t\t}\n\t\t\tlet last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after);\n\t\t\tres |= (last_bits as $rettype) << cur_bit_cursor;\n\t\t\t$selfarg.byte_cursor += octetnum_rounded_up;\n\t\t\t$selfarg.bit_cursor = bit_cursor_after;\n\t\t\t//println!(\" => {:?}\", res);\n\t\t\tOk(res)\n\t\t} else {\n\t\t\t/*println!(\"Reading {} bits (octetnum={}, last_partial={}, total_touched={})\",\n\t\t\t\t$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);\n\t\t\tprintln!(\"    byte_c={}; bit_c={}\", $selfarg.byte_cursor, $selfarg.bit_cursor);// */\n\t\t\t/*print!(\"Reading {} bits (byte_c={}; bit_c={}) [] = {:?}\", $bitnum,\n\t\t\t\t$selfarg.byte_cursor, $selfarg.bit_cursor,\n\t\t\t\t&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +\n\t\t\t\toctetnum_rounded_up]);// */\n\t\t\tif $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() {\n\t\t\t\t//println!(\" => Out of bounds :\\\\\");\n\t\t\t\treturn Err(());\n\t\t\t}\n\t\t\tlet buf = &$selfarg.inner[$selfarg.byte_cursor ..\n\t\t\t\t$selfarg.byte_cursor + octetnum_rounded_up];\n\t\t\tlet mut res :$rettype = buf[0] as $rettype;\n\t\t\tres >>= $selfarg.bit_cursor;\n\t\t\tif $bitnum <= 8 {\n\t\t\t\tres &= mask_bits($bitnum) as $rettype;\n\t\t\t}\n\t\t\tlet mut cur_bit_cursor = 8 - $selfarg.bit_cursor;\n\t\t\tfor i in 1 .. octetnum_rounded_up - 1 {\n\t\t\t\tres |= (buf[i] as $rettype) << cur_bit_cursor;\n\t\t\t\tcur_bit_cursor += 8;\n\t\t\t}\n\t\t\tif $bitnum > 8 {\n\t\t\t\tlet last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after);\n\t\t\t\tres |= (last_bits as $rettype) << cur_bit_cursor;\n\t\t\t}\n\t\t\t$selfarg.byte_cursor += $octetnum;\n\t\t\t$selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize;\n\t\t\t$selfarg.bit_cursor = bit_cursor_after;\n\t\t\t//println!(\" => {:?}\", res);\n\t\t\tOk(res)\n\t\t}\n\t}};\n}\n\n// The main macro to peek bit aligned\n// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)\nmacro_rules! bpc_peek_body {\n\t($rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr) => {{\n\t\tlet last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;\n\t\tlet octetnum_rounded_up :usize = last_octet_partial + $octetnum;\n\t\tlet bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;\n\n\t\tif ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {\n\t\t\t/*println!(\"Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)\",\n\t\t\t\t$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);\n\t\t\tprintln!(\"    byte_c={}; bit_c={}\", $selfarg.byte_cursor, $selfarg.bit_cursor);// */\n\t\t\t/*print!(\"Reading {} bits (byte_c={}; bit_c={}) [] = {:?}\", $bitnum,\n\t\t\t\t$selfarg.byte_cursor, $selfarg.bit_cursor,\n\t\t\t\t&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +\n\t\t\t\t1 + octetnum_rounded_up]);// */\n\t\t\tif $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() {\n\t\t\t\t//println!(\" => Out of bounds :\\\\\");\n\t\t\t\treturn Err(());\n\t\t\t}\n\t\t\tlet buf = &$selfarg.inner[$selfarg.byte_cursor\n\t\t\t\t.. $selfarg.byte_cursor + 1 + octetnum_rounded_up];\n\t\t\tlet mut res :$rettype = buf[0] as $rettype;\n\t\t\tres >>= $selfarg.bit_cursor;\n\t\t\tlet mut cur_bit_cursor = 8 - $selfarg.bit_cursor;\n\t\t\tfor i in 1 .. octetnum_rounded_up {\n\t\t\t\tres |= (buf[i] as $rettype) << cur_bit_cursor;\n\t\t\t\tcur_bit_cursor += 8;\n\t\t\t}\n\t\t\tlet last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after);\n\t\t\tres |= (last_bits as $rettype) << cur_bit_cursor;\n\t\t\t//println!(\" => {:?}\", res);\n\t\t\tOk(res)\n\t\t} else {\n\t\t\t/*println!(\"Reading {} bits (octetnum={}, last_partial={}, total_touched={})\",\n\t\t\t\t$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);\n\t\t\tprintln!(\"    byte_c={}; bit_c={}\", $selfarg.byte_cursor, $selfarg.bit_cursor);// */\n\t\t\t/*print!(\"Reading {} bits (byte_c={}; bit_c={}) [] = {:?}\", $bitnum,\n\t\t\t\t$selfarg.byte_cursor, $selfarg.bit_cursor,\n\t\t\t\t&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +\n\t\t\t\toctetnum_rounded_up]);// */\n\t\t\tif $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() {\n\t\t\t\t//println!(\" => Out of bounds :\\\\\");\n\t\t\t\treturn Err(());\n\t\t\t}\n\t\t\tlet buf = &$selfarg.inner[$selfarg.byte_cursor ..\n\t\t\t\t$selfarg.byte_cursor + octetnum_rounded_up];\n\t\t\tlet mut res :$rettype = buf[0] as $rettype;\n\t\t\tres >>= $selfarg.bit_cursor;\n\t\t\tif $bitnum <= 8 {\n\t\t\t\tres &= mask_bits($bitnum) as $rettype;\n\t\t\t}\n\t\t\tlet mut cur_bit_cursor = 8 - $selfarg.bit_cursor;\n\t\t\tfor i in 1 .. octetnum_rounded_up - 1 {\n\t\t\t\tres |= (buf[i] as $rettype) << cur_bit_cursor;\n\t\t\t\tcur_bit_cursor += 8;\n\t\t\t}\n\t\t\tif $bitnum > 8 {\n\t\t\t\tlet last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after);\n\t\t\t\tres |= (last_bits as $rettype) << cur_bit_cursor;\n\t\t\t}\n\t\t\t//println!(\" => {:?}\", res);\n\t\t\tOk(res)\n\t\t}\n\t}};\n}\n\n// The main macro to advance bit aligned\n// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)\nmacro_rules! bpc_advance_body {\n( $bitnum:expr, $octetnum:expr, $selfarg:expr ) => { {\n\tlet last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;\n\tlet octetnum_rounded_up :usize = last_octet_partial + $octetnum;\n\tlet bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;\n\n\tif ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {\n\t\t$selfarg.byte_cursor += octetnum_rounded_up;\n\t\t$selfarg.bit_cursor = bit_cursor_after;\n\t\t//println!(\" => {:?}\", res);\n\t\tOk(())\n\t} else {\n\t\t$selfarg.byte_cursor += $octetnum;\n\t\t$selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize;\n\t\t$selfarg.bit_cursor = bit_cursor_after;\n\t\t//println!(\" => {:?}\", res);\n\t\tOk(())\n\t}\n} }\n}\n\nmacro_rules! uk_reader {\n\t($fnname:ident, $rettype:ident, $bitnum:expr, $octetnum:expr) => {\n\t\t#[inline]\n\t\tpub fn $fnname(&mut self) -> Result<$rettype, ()> {\n\t\t\tbpc_read_body!($rettype, $bitnum, $octetnum, self)\n\t\t}\n\t};\n}\n\nmacro_rules! ik_reader {\n\t($fnname:ident, $rettype:ident, $bitnum_of_rettype:expr, $bitnum:expr, $octetnum:expr) => {\n\t\t#[inline]\n\t\tpub fn $fnname(&mut self) -> Result<$rettype, ()> {\n\t\t\tOk(sign_extend!(try!(\n\t\t\t\tbpc_read_body!($rettype, $bitnum, $octetnum, self)),\n\t\t\t\t$rettype, $bitnum_of_rettype, $bitnum))\n\t\t}\n\t};\n}\n\nmacro_rules! ik_dynamic_reader {\n\t($fnname:ident, $rettype:ident, $bitnum_of_rettype:expr) => {\n\t\t#[inline]\n\t\tpub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> {\n\t\t\tlet octet_num :usize = (bit_num / 8) as usize;\n\t\t\tassert!(bit_num <= $bitnum_of_rettype);\n\t\t\tOk(sign_extend!(try!(\n\t\t\t\tbpc_read_body!($rettype, bit_num, octet_num, self)),\n\t\t\t\t$rettype, $bitnum_of_rettype, bit_num))\n\t\t}\n\t}\n}\n\nmacro_rules! uk_dynamic_reader {\n\t($fnname:ident, $rettype:ident, $bit_num_max:expr) => {\n\t\t#[inline]\n\t\tpub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> {\n\t\t\tlet octet_num :usize = (bit_num / 8) as usize;\n\t\t\tif bit_num == 0 {\n\t\t\t\t// TODO: one day let bpc_read_body handle this,\n\t\t\t\t// if its smartly doable in there.\n\t\t\t\t// For why it is required, see comment in the\n\t\t\t\t// test_bitpacking_reader_empty function.\n\t\t\t\treturn Ok(0);\n\t\t\t}\n\t\t\tassert!(bit_num <= $bit_num_max);\n\t\t\tbpc_read_body!($rettype, bit_num, octet_num, self)\n\t\t}\n\t};\n}\n\nfn float32_unpack(val :u32) -> f32 {\n\tlet sgn = val & 0x80000000;\n\tlet exp = (val & 0x7fe00000) >> 21;\n\tlet mantissa = (val & 0x1fffff) as f64;\n\tlet signed_mantissa = if sgn != 0 {\n\t\t-mantissa\n\t} else {\n\t\tmantissa\n\t};\n\treturn signed_mantissa as f32 * (exp as f32 - 788.0).exp2();\n}\n\n#[test]\nfn test_float_32_unpack() {\n\t// Values were printed out from what stb_vorbis\n\t// calculated for this function from a test file.\n\tassert_eq!(float32_unpack(1611661312),      1.000000);\n\tassert_eq!(float32_unpack(1616117760),      5.000000);\n\tassert_eq!(float32_unpack(1618345984),     11.000000);\n\tassert_eq!(float32_unpack(1620115456),     17.000000);\n\tassert_eq!(float32_unpack(1627381760),    255.000000);\n\tassert_eq!(float32_unpack(3759144960),     -1.000000);\n\tassert_eq!(float32_unpack(3761242112),     -2.000000);\n\tassert_eq!(float32_unpack(3763339264),     -4.000000);\n\tassert_eq!(float32_unpack(3763601408),     -5.000000);\n\tassert_eq!(float32_unpack(3765436416),     -8.000000);\n\tassert_eq!(float32_unpack(3765829632),    -11.000000);\n\tassert_eq!(float32_unpack(3768451072),    -30.000000);\n\tassert_eq!(float32_unpack(3772628992),   -119.000000);\n\tassert_eq!(float32_unpack(3780634624),  -1530.000000);\n}\n\n#[test]\nfn test_float_32_unpack_issue_24() {\n\t// Regression test for issue #24, a\n\t// mismatch in decoded output for audio_simple_with_error.ogg\n\t// and singlemap-test.ogg.\n\t// The values are taken from the codebook_delta_value and\n\t// codebook_minimum_value values of the singlemap-test.ogg file.\n\t// The expected values come from stb_vorbis.\n\tassert_eq!(float32_unpack(1628434432), 255.0);\n\tassert_eq!(float32_unpack(1621655552), 17.0);\n\tassert_eq!(float32_unpack(1619722240), 11.0);\n\tassert_eq!(float32_unpack(1613234176), 1.0);\n\tassert_eq!(float32_unpack(3760717824), -1.0);\n\tassert_eq!(float32_unpack(3762814976), -2.0);\n\tassert_eq!(float32_unpack(3764912128), -4.0);\n\tassert_eq!(float32_unpack(3765043200), -5.0);\n\tassert_eq!(float32_unpack(3767009280), -8.0);\n\tassert_eq!(float32_unpack(3767205888), -11.0);\n\tassert_eq!(float32_unpack(3769565184), -30.0);\n\tassert_eq!(float32_unpack(3773751296), -119.0);\n\tassert_eq!(float32_unpack(3781948416), -1530.0);\n}\n\n// allow some code that is only used in the tests\n#[allow(dead_code)]\nimpl <'a> BitpackCursor <'a> {\n\n\t/// Creates a new `BitpackCursor` for the given data array\n\tpub fn new(arr : &'a[u8]) -> BitpackCursor {\n\t\treturn BitpackCursor::<'a> { bit_cursor: 0, byte_cursor: 0, inner: arr };\n\t}\n\n\t// Unsigned, non-dynamic reader methods\n\n\t// u32 based\n\n\t// TODO add here if needed\n\tuk_reader!(read_u32, u32, 32, 4);\n\t// TODO add here if needed\n\tuk_reader!(read_u24, u32, 24, 3);\n\t// TODO add here if needed\n\n\t// u16 based\n\n\tuk_reader!(read_u16, u16, 16, 2);\n\n\t// TODO add here if needed\n\tuk_reader!(read_u13, u16, 13, 1);\n\t// TODO add here if needed\n\n\t// u8 based\n\tuk_reader!(read_u8, u8, 8, 1);\n\tuk_reader!(read_u7, u8, 7, 0);\n\tuk_reader!(read_u6, u8, 6, 0);\n\tuk_reader!(read_u5, u8, 5, 0);\n\tuk_reader!(read_u4, u8, 4, 0);\n\tuk_reader!(read_u3, u8, 3, 0);\n\tuk_reader!(read_u2, u8, 2, 0);\n\tuk_reader!(read_u1, u8, 1, 0);\n\n\t// Returning bool:\n\t#[inline]\n\tpub fn read_bit_flag(&mut self) -> Result<bool, ()> {\n\t\treturn Ok(try!(self.read_u1()) == 1);\n\t}\n\n\t// Unsigned dynamic reader methods\n\t// They panic if you give them invalid params\n\t// (bit_num larger than maximum allowed bit number for the type)\n\tuk_dynamic_reader!(read_dyn_u8,  u8,  8);\n\tuk_dynamic_reader!(read_dyn_u16, u16, 16);\n\tuk_dynamic_reader!(read_dyn_u32, u32, 32);\n\tuk_dynamic_reader!(read_dyn_u64, u64, 64);\n\n\t// Signed non-dynamic reader methods\n\n\tik_reader!(read_i32, i32, 32, 32, 4);\n\t// TODO add here if needed\n\n\tik_reader!(read_i8, i8, 8, 8, 1);\n\tik_reader!(read_i7, i8, 8, 7, 0);\n\t// TODO add here if needed\n\n\t// Signed dynamic reader methods\n\t// They panic if you give them invalid params\n\t// (bit_num larger than maximum allowed bit number for the type)\n\tik_dynamic_reader!(read_dyn_i8,  i8,  8);\n\tik_dynamic_reader!(read_dyn_i16, i16, 16);\n\tik_dynamic_reader!(read_dyn_i32, i32, 32);\n\n\t// Float reading methods\n\n\t/// Reads a single floating point number in the vorbis-float32 format\n\tpub fn read_f32(&mut self) -> Result<f32, ()> {\n\t\tlet val = try!(self.read_u32());\n\t\tOk(float32_unpack(val))\n\t}\n\n\t/// Peeks 8 bits of non read yet content without advancing the reader\n\t#[inline]\n\tpub fn peek_u8(&self) -> Result<u8, ()> {\n\t\tbpc_peek_body!(u8, 8, 1, self)\n\t}\n\n\t// Advances the reader by the given number of bits (up to 8).\n\tpub fn advance_dyn_u8(&mut self, bit_num :u8) -> Result<(), ()> {\n\t\tlet octet_num :usize = (bit_num / 8) as usize;\n\t\tif bit_num == 0 {\n\t\t\t// TODO: one day let bpc_advance_body handle this,\n\t\t\t// if its smartly doable in there.\n\t\t\t// For why it is required, see comment in the\n\t\t\t// test_bitpacking_reader_empty function.\n\t\t\treturn Ok(());\n\t\t}\n\t\tassert!(bit_num <= 8);\n\t\tbpc_advance_body!(bit_num, octet_num, self)\n\t}\n\n\t/// Reads a huffman word using the codebook abstraction\n\tpub fn read_huffman(&mut self, tree :&VorbisHuffmanTree) -> Result<u32, ()> {\n\t\t//let mut c :usize = 0;\n\t\t//let mut w :usize = 0;\n\t\tlet mut iter = match self.peek_u8() {\n\t\t\tOk(data) => match tree.lookup_peeked_data(8, data as u32) {\n\t\t\t\tPeekedDataLookupResult::Iter(advance, iter) => {\n\t\t\t\t\ttry!(self.advance_dyn_u8(advance));\n\t\t\t\t\titer\n\t\t\t\t},\n\t\t\t\tPeekedDataLookupResult::PayloadFound(advance, payload) => {\n\t\t\t\t\ttry!(self.advance_dyn_u8(advance));\n\t\t\t\t\treturn Ok(payload);\n\t\t\t\t},\n\t\t\t},\n\t\t\tErr(_) => tree.iter(),\n\t\t};\n\n\t\tloop {\n\t\t\tlet b = try!(self.read_bit_flag());\n\t\t\t/*\n\t\t\tc +=1;\n\t\t\tw >>= 1;\n\t\t\tw |= (b as usize) << 63;\n\t\t\t// Put this into the Some arm of the match below in order to debug:\n\t\t\t{print!(\"({}:{}:{}) \", w >> (64 - c), v, c); }\n\t\t\t// */\n\t\t\tmatch iter.next(b) {\n\t\t\t\tSome(v) => return Ok(v),\n\t\t\t\tNone => (),\n\t\t\t}\n\t\t}\n\t}\n}\n\n#[test]\nfn test_bitpacking_reader_static() {\n\t// Test vectors taken from Vorbis I spec, section 2.1.6\n\tlet test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_u4().unwrap(),  12);\n\tassert_eq!(cur.read_u3().unwrap(),  7);\n\tassert_eq!(cur.read_u7().unwrap(),  17);\n\tassert_eq!(cur.read_u13().unwrap(), 6969);\n}\n\n#[test]\nfn test_bitpacking_reader_dynamic() {\n\t// Test vectors taken from Vorbis I spec, section 2.1.6\n\tlet test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_dyn_u8(4).unwrap(),   12);\n\tassert_eq!(cur.read_dyn_u8(3).unwrap(),   7);\n\tassert_eq!(cur.read_dyn_u16(7).unwrap(),  17);\n\tassert_eq!(cur.read_dyn_u16(13).unwrap(), 6969);\n\n\t// Regression test for bug\n\tlet test_arr = &[93, 92];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_dyn_u32(10).unwrap(), 93);\n}\n\n#[test]\nfn test_bitpacking_reader_empty() {\n\t// Same as the normal bitpacking test\n\t// but with some additional empty reads.\n\t//\n\t// This is expected to happen by the vorbis spec.\n\t// For example, the mode_number read in the audio packet\n\t// decode at first position may be 0 bit long (if there\n\t// is only one mode, ilog([vorbis_mode_count] - 1) is zero).\n\n\tlet test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_dyn_u8(4).unwrap(),   12);\n\tassert_eq!(cur.read_dyn_u8(0).unwrap(),   0);\n\tassert_eq!(cur.read_dyn_u8(0).unwrap(),   0);\n\tassert_eq!(cur.read_dyn_u8(3).unwrap(),   7);\n\tassert_eq!(cur.read_dyn_u8(0).unwrap(),   0);\n\tassert_eq!(cur.read_dyn_u16(7).unwrap(),  17);\n\tassert_eq!(cur.read_dyn_u16(0).unwrap(),   0);\n\tassert_eq!(cur.read_dyn_u16(0).unwrap(),   0);\n\tassert_eq!(cur.read_dyn_u16(13).unwrap(), 6969);\n\tassert_eq!(cur.read_dyn_u16(0).unwrap(),   0);\n}\n\n#[test]\nfn test_bitpacking_reader_byte_aligned() {\n\t// Check that bitpacking readers work with \"normal\" byte aligned types:\n\tlet test_arr = &[0x00, 0x00, 0x00, 0x00, 0x01];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_dyn_u32(32).unwrap(), 0);\n\tassert_eq!(cur.read_dyn_u8(8).unwrap(),   1);\n\n\t// We not just check here whether it works for byte aligned\n\t// \"normal\" (non-dynamic) reader methods, we also check\n\t// whether, after reading first one, then seven bits,\n\t// it \"gets back\" to byte alignment (and increases the byte ctr)\n\tlet test_arr = &[0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tassert_eq!(cur.read_u1().unwrap(), 1);\n\tassert_eq!(cur.read_u7().unwrap(), 4);\n\tassert_eq!(cur.read_i8().unwrap(), 2);\n\tassert_eq!(cur.read_u32().unwrap(), 0);\n\tassert_eq!(cur.read_u8().unwrap(), 1);\n}\n\n#[test]\nfn test_capture_pattern_nonaligned() {\n\t// Regression test from test OGG file\n\t// Tests for proper codebook capture\n\t// pattern reading.\n\t//\n\t// The OGG vorbis capture pattern\n\t// is a three octet (24 bits) value.\n\t//\n\t// The first block tests capture pattern\n\t// reading in a byte aligned scenario.\n\t// The actually problematic part was\n\t// the second block: it tests capture\n\t// pattern reading in a non-aligned\n\t// situation.\n\n\tlet capture_pattern_arr = &[0x42, 0x43, 0x56];\n\tlet mut cur = BitpackCursor::new(capture_pattern_arr);\n\tassert_eq!(cur.read_u24().unwrap(), 0x564342);\n\n\tlet test_arr = &[0x28, 0x81, 0xd0, 0x90, 0x55, 0x00, 0x00];\n\tlet mut cur = BitpackCursor::new(test_arr);\n\tcur.read_u5().unwrap(); // some value we are not interested in\n\tcur.read_u5().unwrap(); // some value we are not interested in\n\tassert_eq!(cur.read_u4().unwrap(), 0);\n\tassert_eq!(cur.read_u24().unwrap(), 0x564342);\n\t// Ensure that we incremented by only three bytes, not four\n\tassert_eq!(cur.read_u16().unwrap(), 1);\n}\n"
  },
  {
    "path": "src/capi.rs",
    "content": "use std::os::raw::c_int;\nuse std::slice::from_raw_parts;\nuse std::ptr::null_mut;\n\nuse header::{read_header_setup, //read_header_comment,\n\tread_header_ident, IdentHeader, //CommentHeader,\n\tSetupHeader};\nuse audio::{PreviousWindowRight, read_audio_packet_generic};\n\n/// Main Decoder State\n///\n/// It is created by `lewton_context_from_extradata` by passing a xiph-laced extradate bundle\npub struct LewtonContext {\n\tpwr :PreviousWindowRight,\n\n\tident_hdr :IdentHeader,\n\t//comment_hdr :CommentHeader,\n\tsetup_hdr :SetupHeader,\n}\n\nfn read_xiph_lacing(arr :&mut &[u8]) -> Option<u64> {\n\tlet mut r = 0;\n\tloop {\n\t\tif arr.len() == 0 {\n\t\t\treturn None;\n\t\t}\n\t\tlet v = arr[0] as u64;\n\t\t*arr = &arr[1..];\n\t\tr += v;\n\t\tif v < 255 {\n\t\t\treturn Some(r);\n\t\t}\n\t}\n}\n\nimpl LewtonContext {\n\tfn from_extradata(mut extradata :&[u8]) -> Option<Self> {\n\t\t// We must start with a 2 as per matroska encapsulation spec\n\t\tif extradata.len() == 0 || extradata[0] != 2 {\n\t\t\treturn None\n\t\t}\n\t\textradata = &extradata[1..];\n\t\tlet ident_len = read_xiph_lacing(&mut extradata)? as usize;\n\t\tlet comment_len = read_xiph_lacing(&mut extradata)? as usize;\n\n\t\tlet ident_hdr = read_header_ident(&extradata[0..ident_len]).ok()?;\n\t\textradata = &extradata[ident_len..];\n\t\t//let comment_hdr = read_header_comment(&extradata[0..comment_len]).ok()?;\n\t\textradata = &extradata[comment_len..];\n\t\tlet setup_hdr = read_header_setup(extradata, ident_hdr.audio_channels,\n\t\t\t(ident_hdr.blocksize_0, ident_hdr.blocksize_1))\n\t\t\t.ok()?;\n\t\tSome(LewtonContext {\n\t\t\tpwr : PreviousWindowRight::new(),\n\n\t\t\tident_hdr,\n\t\t\t//comment_hdr,\n\t\t\tsetup_hdr,\n\t\t})\n\t}\n}\n\n/// A multichannel vector of samples\n///\n/// It is produced by `lewton_decode_packet`\n///\n/// Use `lewton_samples_count` to retrieve the number of samples available in each channel\n/// Use `lewton_samples_channels` to retrieve the number of channels\n/// Use `lewton_samples_for_channel_f32` to retrieve a reference to the data present in the\n/// channel\n///\n/// use `lewton_samples_drop()` to deallocate the memory\npub struct LewtonSamples(Vec<Vec<f32>>);\n\n/// Create a LewtonContext from an extradata buffer\n///\n/// Returns either NULL or a newly allocated LewtonContext\n#[no_mangle]\npub unsafe extern fn lewton_context_from_extradata(\n\t\tdata :*const u8, len :usize) -> *mut LewtonContext {\n\tif data.is_null() {\n\t\treturn null_mut();\n\t}\n\tlet extradata = from_raw_parts(data, len);\n\tif let Some(cx) = LewtonContext::from_extradata(extradata) {\n\t\tlet boxed = Box::new(cx);\n\t\tBox::into_raw(boxed)\n\t} else {\n\t\tnull_mut()\n\t}\n}\n\n/// Reset the Decoder to support seeking.\n#[no_mangle]\npub unsafe extern fn lewton_context_reset(ctx :*mut LewtonContext) {\n\t(*ctx).pwr = PreviousWindowRight::new();\n}\n\n/// Decode a packet to LewtonSamples when possible\n///\n/// Returns 0 on success, non-zero if no samples can be produced\n#[no_mangle]\npub unsafe extern fn lewton_decode_packet(ctx :*mut LewtonContext,\n\t\tpkt :*const u8, len: usize,\n\t\tsample_out :*mut *mut LewtonSamples) -> c_int {\n\tif pkt.is_null() || ctx.is_null() || sample_out.is_null() {\n\t\treturn 1;\n\t}\n\tlet pkt = from_raw_parts(pkt, len);\n\tlet decoded = read_audio_packet_generic(&(*ctx).ident_hdr,\n\t\t\t&(*ctx).setup_hdr, &pkt, &mut (*ctx).pwr);\n\tlet decoded = if let Ok(v) = decoded {\n\t\tv\n\t} else {\n\t\treturn 2;\n\t};\n\tlet boxed = Box::new(LewtonSamples(decoded));\n\t*sample_out = Box::into_raw(boxed);\n\treturn 0;\n}\n\n/// Provide the number of samples present in each channel\n#[no_mangle]\npub unsafe extern fn lewton_samples_count(samples :*const LewtonSamples) -> usize {\n\t(*samples).0\n\t\t.get(0)\n\t\t.map(|v| v.len())\n\t\t.unwrap_or(0)\n}\n\n/// Provide a reference to the channel sample data\npub unsafe extern fn lewton_samples_f32(samples :*const LewtonSamples, channel :usize) -> *const f32 {\n\t(*samples).0\n\t\t.get(channel)\n\t\t.map(|v| v.as_ptr())\n\t\t.unwrap_or(std::ptr::null())\n}\n\n#[no_mangle]\npub unsafe extern fn lewton_samples_drop(samples :*mut LewtonSamples) {\n\tstd::mem::drop(Box::from_raw(samples));\n}\n\n#[no_mangle]\npub unsafe extern fn lewton_context_drop(ctx :*mut LewtonContext) {\n\tstd::mem::drop(Box::from_raw(ctx));\n}\n"
  },
  {
    "path": "src/header.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nHeader decoding\n\nThis module takes care of decoding of the three vorbis headers:\n\n1. Identification\n2. Comment\n3. Setup\n\nIt builds only on the internal bitpacking layer and the internal\nhuffman tree handling mod. Everything else about the headers is\ndecoded in this mod.\n*/\n\nuse std::error;\nuse std::fmt;\nuse std::io::{Cursor, ErrorKind, Read, Error};\nuse std::string::FromUtf8Error;\nuse byteorder::{ReadBytesExt, LittleEndian};\nuse header_cached::{CachedBlocksizeDerived, compute_bark_map_cos_omega};\nuse bitpacking::BitpackCursor;\nuse huffman_tree::{VorbisHuffmanTree, HuffmanError};\n\n/// Errors that can occur during Header decoding\n#[derive(Debug)]\n#[derive(PartialEq)]\npub enum HeaderReadError {\n\tEndOfPacket,\n\t/// If the passed data don't start with the \"vorbis\"\n\t/// capture pattern, this error is returned.\n\tNotVorbisHeader,\n\tUnsupportedVorbisVersion,\n\t/// If the header violates the vorbis spec\n\tHeaderBadFormat,\n\t/// The given packet indeed seems to be a vorbis header,\n\t/// but it looks like it is a different header type than\n\t/// the function it was passed to.\n\t///\n\t/// It is not guaranteed that the type is a valid header type.\n\tHeaderBadType(u8),\n\t/// The given packet does not seem to be a header as per vorbis spec,\n\t/// instead it seems to be an audio packet.\n\tHeaderIsAudio,\n\tUtf8DecodeError,\n\t/// If the needed memory isn't addressable by us\n\t///\n\t/// This error is returned if a calculation yielded a higher value for\n\t/// an internal buffer size that doesn't fit into the platform's address range.\n\t/// Note that if we \"simply\" encounter an allocation failure (OOM, etc),\n\t/// we do what libstd does in these cases: crash.\n\t///\n\t/// This error is not automatically an error of the passed data,\n\t/// but rather is due to insufficient decoder hardware.\n\tBufferNotAddressable,\n}\n\n// For the () error type returned by the bitpacking layer\n// TODO that type choice was a bit unfortunate,\n// perhaps one day fix this\nimpl From<()> for HeaderReadError {\n\tfn from(_ :()) -> HeaderReadError {\n\t\tHeaderReadError::EndOfPacket\n\t}\n}\n\nimpl From<HuffmanError> for HeaderReadError {\n\tfn from(_ :HuffmanError) -> HeaderReadError {\n\t\tHeaderReadError::HeaderBadFormat\n\t}\n}\n\nimpl From<Error> for HeaderReadError {\n\tfn from(err :Error) -> HeaderReadError {\n\t\tmatch err.kind() {\n\t\t\tErrorKind::UnexpectedEof => HeaderReadError::EndOfPacket,\n\t\t\t_ => panic!(\"Non EOF Error occured when reading from Cursor<&[u8]>: {}\", err),\n\t\t}\n\t}\n}\n\nimpl From<FromUtf8Error> for HeaderReadError {\n\tfn from(_ :FromUtf8Error) -> HeaderReadError {\n\t\tHeaderReadError::Utf8DecodeError\n\t}\n}\n\nimpl error::Error for HeaderReadError {}\n\nimpl fmt::Display for HeaderReadError {\n\tfn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {\n\t\tlet description = match self {\n\t\t\tHeaderReadError::EndOfPacket => \"End of packet reached.\",\n\t\t\tHeaderReadError::NotVorbisHeader => \"The packet is not a vorbis header\",\n\t\t\tHeaderReadError::UnsupportedVorbisVersion => \"The vorbis version is not supported\",\n\t\t\tHeaderReadError::HeaderBadFormat => \"Invalid header\",\n\t\t\tHeaderReadError::HeaderBadType(_) => \"Invalid/unexpected header type\",\n\t\t\tHeaderReadError::HeaderIsAudio => \"Packet seems to be audio\",\n\t\t\tHeaderReadError::Utf8DecodeError => \"UTF-8 decoding error\",\n\t\t\tHeaderReadError::BufferNotAddressable => \"Requested to create buffer of non-addressable size\",\n\t\t};\n\t\twrite!(fmt, \"{}\", description)\n\t}\n}\n\n/// Macro to convert values of any unsigned integral non-usize type to\n/// usize, and then check whether there had been any losses due to conversion.\n///\n/// If there were, it will return the BufferNotAddressable error.\nmacro_rules! convert_to_usize {\n( $val:expr, $val_type:ident ) => { {\n\tlet converted :usize = $val as usize;\n\tif $val != converted as $val_type {\n\t\ttry!(Err(HeaderReadError::BufferNotAddressable));\n\t}\n\tconverted\n}}\n}\n\n// Internal function, tries to find out whether the\n// data returned by rdr belong to a vorbis header\n// On success it returns Some(n) with n as packet type\n// (you must check that n from 1,3,5)\nmacro_rules! read_header_begin_body {\n( $rdr:expr ) => { {\n\tlet res = try!($rdr.read_u8());\n\tif res & 1 == 0 {\n\t\t// This is an audio packet per vorbis spec, if anything.\n\t\t// (audio packets have their first bit set to 0,\n\t\t// header packets have it set to 1)\n\t\ttry!(Err(HeaderReadError::HeaderIsAudio));\n\t}\n\tlet is_vorbis =\n\t\ttry!($rdr.read_u8()) == 0x76 && // 'v'\n\t\ttry!($rdr.read_u8()) == 0x6f && // 'o'\n\t\ttry!($rdr.read_u8()) == 0x72 && // 'r'\n\t\ttry!($rdr.read_u8()) == 0x62 && // 'b'\n\t\ttry!($rdr.read_u8()) == 0x69 && // 'i'\n\t\ttry!($rdr.read_u8()) == 0x73;   // 's'\n\tif !is_vorbis {\n\t\ttry!(Err(HeaderReadError::NotVorbisHeader));\n\t}\n\treturn Ok(res);\n}}\n}\nfn read_header_begin(rdr :&mut BitpackCursor) -> Result<u8, HeaderReadError> {\n\tread_header_begin_body!(rdr)\n}\nfn read_header_begin_cursor(rdr :&mut Cursor<&[u8]>) -> Result<u8, HeaderReadError> {\n\tread_header_begin_body!(rdr)\n}\n\n\n#[test]\nfn test_read_hdr_begin() {\n\t// Only tests flawed header begins, correct headers\n\t// are tested later by the test methods for the headers\n\n\t// Flawed ident header (see char before the /**/)\n\tlet test_arr = &[0x01, 0x76, 0x6f, 0x72,\n\t0x62, 0x69, 0x72, /**/ 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x44, 0xac, 0x00,      0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x80, 0xb5, 0x01,      0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xb8, 0x01];\n\tlet mut rdr :BitpackCursor = BitpackCursor::new(test_arr);\n\tassert_eq!(read_header_begin(&mut rdr), Err(HeaderReadError::NotVorbisHeader));\n}\n\n/// The set of the three Vorbis headers\npub type HeaderSet = (IdentHeader, CommentHeader, SetupHeader);\n\n/**\nRepresentation for the identification header\n\nThe identification header is the first of the three\nheaders inside each vorbis stream.\n\nIt covers basic information about the stream.\n*/\n#[derive(Clone)]\npub struct IdentHeader {\n\t/// The number of audio channels in the stream\n\tpub audio_channels :u8,\n\t/// The sample rate of the stream\n\tpub audio_sample_rate :u32,\n\t/// The maximum bit rate of the stream\n\t///\n\t/// Note that this value is only a hint\n\t/// and may be off by a large amount.\n\tpub bitrate_maximum :i32,\n\t/// The nominal bit rate of the stream\n\t///\n\t/// Note that this value is only a hint\n\t/// and may be off by a large amount.\n\tpub bitrate_nominal :i32,\n\t/// The minimum bit rate of the stream\n\t///\n\t/// Note that this value is only a hint\n\t/// and may be off by a large amount.\n\tpub bitrate_minimum :i32,\n\tpub blocksize_0 :u8,\n\tpub blocksize_1 :u8,\n\tpub(crate) cached_bs_derived :[CachedBlocksizeDerived; 2],\n}\n\n/**\nReading the Identification header\n\nIf it returns Err(sth) when being called with the first packet in a stream,\nthe whole stream is to be considered undecodable as per the Vorbis spec.\nThe function returns Err(`HeaderReadError::HeaderBadType`) if the header type\ndoesn't match the ident header.\n*/\npub fn read_header_ident(packet :&[u8]) -> Result<IdentHeader, HeaderReadError> {\n\tlet mut rdr = BitpackCursor::new(packet);\n\tlet hd_id = try!(read_header_begin(&mut rdr));\n\tif hd_id != 1 {\n\t\ttry!(Err(HeaderReadError::HeaderBadType(hd_id)));\n\t}\n\tlet vorbis_version = try!(rdr.read_u32());\n\tif vorbis_version != 0 {\n\t\ttry!(Err(HeaderReadError::UnsupportedVorbisVersion));\n\t}\n\tlet audio_channels = try!(rdr.read_u8());\n\tlet audio_sample_rate = try!(rdr.read_u32());\n\tlet bitrate_maximum = try!(rdr.read_i32());\n\tlet bitrate_nominal = try!(rdr.read_i32());\n\tlet bitrate_minimum = try!(rdr.read_i32());\n\tlet blocksize_0 = try!(rdr.read_u4());\n\tlet blocksize_1 = try!(rdr.read_u4());\n\tlet framing = try!(rdr.read_u8());\n\tif blocksize_0 < 6 || blocksize_0 > 13 ||\n\t\t\tblocksize_1 < 6 || blocksize_1 > 13 ||\n\t\t\t(framing != 1) || blocksize_0 > blocksize_1 ||\n\t\t\taudio_channels == 0 || audio_sample_rate == 0 {\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet hdr :IdentHeader = IdentHeader {\n\t\taudio_channels,\n\t\taudio_sample_rate,\n\t\tbitrate_maximum,\n\t\tbitrate_nominal,\n\t\tbitrate_minimum,\n\t\tblocksize_0,\n\t\tblocksize_1,\n\t\tcached_bs_derived : [\n\t\t\tCachedBlocksizeDerived::from_blocksize(blocksize_0),\n\t\t\tCachedBlocksizeDerived::from_blocksize(blocksize_1),\n\t\t],\n\t};\n\treturn Ok(hdr);\n}\n\n#[test]\nfn test_read_header_ident() {\n\t// Valid ident header\n\tlet test_arr = &[0x01, 0x76, 0x6f, 0x72,\n\t0x62, 0x69, 0x73, 0x00, 0x00, 0x00, 0x00, 0x02,\n\t0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0x80, 0xb5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,\n\t0xb8, 0x01];\n\tlet hdr = read_header_ident(test_arr).unwrap();\n\tassert_eq!(hdr.audio_channels, 2);\n\tassert_eq!(hdr.audio_sample_rate, 0x0000ac44);\n\tassert_eq!(hdr.bitrate_maximum, 0);\n\tassert_eq!(hdr.bitrate_nominal, 0x0001b580);\n\tassert_eq!(hdr.bitrate_minimum, 0);\n\tassert_eq!(hdr.blocksize_0, 8);\n\tassert_eq!(hdr.blocksize_1, 11);\n}\n\n/**\nRepresentation of the comment header\n\nThe comment header is the second of the three\nheaders inside each vorbis stream.\n\nIt contains text comment metadata\nabout the stream, encoded as key-value pairs,\nand the vendor name.\n*/\n#[derive(Clone, PartialEq, Eq, Hash, Debug)]\npub struct CommentHeader {\n\t/// An identification string of the\n\t/// software/library that encoded\n\t/// the stream.\n\tpub vendor :String,\n\t/// A key-value list of the comments\n\t/// attached to the stream.\n\tpub comment_list :Vec<(String, String)>,\n}\n\n/**\nReading the Comment header\n\nYou should call this function with the second packet in the stream.\n\nThe function does not check whether the comment field names consist\nof characters `0x20` through `0x7D` (`0x3D` excluded), as the vorbis\nspec requires.\n*/\npub fn read_header_comment(packet :&[u8]) -> Result<CommentHeader, HeaderReadError> {\n\tlet mut rdr = Cursor::new(packet);\n\tlet hd_id = try!(read_header_begin_cursor(&mut rdr));\n\tif hd_id != 3 {\n\t\ttry!(Err(HeaderReadError::HeaderBadType(hd_id)));\n\t}\n\t// First read the vendor string\n\tlet vendor_length = try!(rdr.read_u32::<LittleEndian>()) as usize;\n\tlet mut vendor_buf = vec![0; vendor_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as \"unsafe\" by rustc.\n\ttry!(rdr.read_exact(&mut vendor_buf));\n\tlet vendor = try!(String::from_utf8(vendor_buf));\n\n\t// Now read the comments\n\tlet comment_count = try!(rdr.read_u32::<LittleEndian>()) as usize;\n\tlet mut comment_list = Vec::with_capacity(comment_count);\n\tfor _ in 0 .. comment_count {\n\t\tlet comment_length = try!(rdr.read_u32::<LittleEndian>()) as usize;\n\t\tlet mut comment_buf = vec![0; comment_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as \"unsafe\" by rustc.\n\t\ttry!(rdr.read_exact(&mut comment_buf));\n\t\tlet comment = match String::from_utf8(comment_buf) {\n\t\t\tOk(comment) => comment,\n\t\t\t// Uncomment for closer compliance with the spec.\n\t\t\t// The spec explicitly states that the comment entries\n\t\t\t// should be UTF-8 formatted, however it seems that other\n\t\t\t// decoder libraries tolerate non-UTF-8 formatted strings\n\t\t\t// in comments. This has led to some files circulating\n\t\t\t// with such errors inside. If we deny to decode such files,\n\t\t\t// lewton would be the odd one out. Thus we just\n\t\t\t// gracefully ignore them.\n\t\t\tErr(_) => continue,\n\t\t};\n\t\tlet eq_idx = match comment.find(\"=\") {\n\t\t\tSome(k) => k,\n\t\t\t// Uncomment for closer compliance with the spec.\n\t\t\t// It appears that some ogg files have fields without a = sign in the comments.\n\t\t\t// Well there is not much we can do but gracefully ignore their stuff.\n\t\t\tNone => continue // try!(Err(HeaderReadError::HeaderBadFormat))\n\t\t};\n\t\tlet (key_eq, val) = comment.split_at(eq_idx + 1);\n\t\tlet (key, _) = key_eq.split_at(eq_idx);\n\t\tcomment_list.push((String::from(key), String::from(val)));\n\t}\n\tlet framing = try!(rdr.read_u8());\n\tif framing != 1 {\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet hdr :CommentHeader = CommentHeader {\n\t\tvendor,\n\t\tcomment_list,\n\t};\n\treturn Ok(hdr);\n}\n\n#[derive(Clone)]\npub(crate) struct Codebook {\n\tpub codebook_dimensions :u16,\n\n\t// None if codebook_lookup_type == 0\n\tpub codebook_vq_lookup_vec :Option<Vec<f32>>,\n\n\tpub codebook_huffman_tree :VorbisHuffmanTree,\n}\n\n#[derive(Clone)]\npub(crate) struct Residue {\n\tpub residue_type :u8,\n\tpub residue_begin :u32,\n\tpub residue_end :u32,\n\tpub residue_partition_size :u32,\n\tpub residue_classifications :u8,\n\tpub residue_classbook :u8,\n\tpub residue_books :Vec<ResidueBook>,\n}\n\n#[derive(Clone)]\npub(crate) struct Mapping {\n\tpub mapping_magnitudes :Vec<u8>,\n\tpub mapping_angles :Vec<u8>,\n\tpub mapping_mux :Vec<u8>,\n\tpub mapping_submap_floors :Vec<u8>,\n\tpub mapping_submap_residues :Vec<u8>,\n}\n\n#[derive(Clone)]\npub(crate) struct ModeInfo {\n\tpub mode_blockflag :bool,\n\tpub mode_mapping :u8,\n}\n\n#[derive(Clone)]\npub(crate) enum Floor {\n\tTypeZero(FloorTypeZero),\n\tTypeOne(FloorTypeOne),\n}\n\n#[derive(Clone)]\npub(crate) struct FloorTypeZero {\n\tpub floor0_order :u8,\n\tpub floor0_amplitude_bits :u8,\n\tpub floor0_amplitude_offset :u8,\n\tpub floor0_number_of_books :u8,\n\tpub floor0_book_list :Vec<u8>,\n\tpub cached_bark_cos_omega :[Vec<f32>; 2],\n}\n\n#[derive(Clone)]\npub(crate) struct FloorTypeOne {\n\tpub floor1_multiplier :u8,\n\tpub floor1_partition_class :Vec<u8>,\n\tpub floor1_class_dimensions :Vec<u8>,\n\tpub floor1_class_subclasses :Vec<u8>,\n\tpub floor1_subclass_books :Vec<Vec<i16>>,\n\tpub floor1_class_masterbooks :Vec<u8>,\n\tpub floor1_x_list :Vec<u32>,\n\tpub floor1_x_list_sorted :Vec<(usize, u32)>,\n}\n\n#[derive(Clone)]\npub(crate) struct ResidueBook {\n\tvals_used :u8,\n\tval_i :[u8; 8],\n}\n\nimpl ResidueBook {\n\tpub fn get_val(&self, i :u8) -> Option<u8> {\n\t\tif i >= 8 {\n\t\t\t// This is a precondition...\n\t\t\tpanic!(\"Tried to get ResidueBook value out of bounds (index = {})\",\n\t\t\t\ti);\n\t\t}\n\t\treturn if self.vals_used & (1 << i) > 0 {\n\t\t\tSome(self.val_i[i as usize])\n\t\t} else {\n\t\t\tNone\n\t\t};\n\t}\n\t/// Reads the `ResidueBook` from a `BitpackCursor`.\n\tfn read_book(rdr :&mut BitpackCursor,\n\t\t\tvals_used :u8, codebooks :&[Codebook])\n\t\t\t-> Result<Self, HeaderReadError> {\n\t\tlet mut val_i :[u8; 8] = [0; 8];\n\t\tfor i in 0 .. 7 {\n\t\t\tif vals_used & (1 << i) == 0 {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlet val_entry = try!(rdr.read_u8());\n\t\t\tif match codebooks.get(val_entry as usize) {\n\t\t\t\tSome(v) => v.codebook_vq_lookup_vec.is_none(),\n\t\t\t\tNone => true,\n\t\t\t} {\n\t\t\t\t// Both of the cases are forbidden by spec\n\t\t\t\t// (the codebook being out of bounds, or\n\t\t\t\t// not having a value mapping)\n\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat))\n\t\t\t}\n\t\t\tval_i[i] = val_entry;\n\t\t}\n\t\treturn Ok(ResidueBook { vals_used, val_i });\n\t}\n}\n\n#[derive(Clone)]\npub struct SetupHeader {\n\tpub(crate) codebooks :Vec<Codebook>,\n\tpub(crate) floors :Vec<Floor>,\n\tpub(crate) residues :Vec<Residue>,\n\tpub(crate) mappings :Vec<Mapping>,\n\tpub(crate) modes :Vec<ModeInfo>,\n}\n\nstruct CodebookVqLookup {\n\tcodebook_lookup_type :u8,\n\tcodebook_minimum_value :f32,\n\tcodebook_delta_value :f32,\n\tcodebook_sequence_p :bool,\n\tcodebook_multiplicands :Vec<u32>,\n}\n\n/// Vector value decode for lookup\n///\n/// Prepares the VQ context vectors for later lookup\n/// by the codebook abstraction layer.\n///\n/// Returns `codebook_entries` many vectors,\n/// each being `codebook_dimensions` scalars wide),\n/// all stored in one Vec.\nfn lookup_vec_val_decode(lup :&CodebookVqLookup, codebook_entries :u32, codebook_dimensions :u16) -> Vec<f32> {\n\tlet mut value_vectors = Vec::with_capacity(\n\t\tcodebook_entries as usize * codebook_dimensions as usize);\n\tif lup.codebook_lookup_type == 1 {\n\t\tlet codebook_lookup_values = lup.codebook_multiplicands.len();\n\t\tfor lookup_offset in 0 .. codebook_entries {\n\t\t\tlet mut last = 0.;\n\t\t\tlet mut index_divisor = 1;\n\t\t\tfor _ in 0 .. codebook_dimensions {\n\t\t\t\tlet multiplicand_offset = (lookup_offset / index_divisor as u32) as usize %\n\t\t\t\t\tcodebook_lookup_values;\n\t\t\t\tlet vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 *\n\t\t\t\t\tlup.codebook_delta_value + lup.codebook_minimum_value + last;\n\t\t\t\tif lup.codebook_sequence_p {\n\t\t\t\t\tlast = vec_elem;\n\t\t\t\t}\n\t\t\t\tvalue_vectors.push(vec_elem);\n\t\t\t\tindex_divisor *= codebook_lookup_values;\n\t\t\t}\n\t\t}\n\t} else {\n\t\tfor lookup_offset in 0 .. codebook_entries {\n\t\t\tlet mut last = 0.;\n\t\t\tlet mut multiplicand_offset :usize = lookup_offset as usize * codebook_dimensions as usize;\n\t\t\tfor _ in 0 .. codebook_dimensions {\n\t\t\t\tlet vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 *\n\t\t\t\t\tlup.codebook_delta_value + lup.codebook_minimum_value + last;\n\t\t\t\tif lup.codebook_sequence_p {\n\t\t\t\t\tlast = vec_elem;\n\t\t\t\t}\n\t\t\t\tvalue_vectors.push(vec_elem);\n\t\t\t\tmultiplicand_offset += 1;\n\t\t\t}\n\t\t}\n\t}\n\treturn value_vectors;\n}\n\n\n/// Small Error type for `BitpackCursor::read_huffman_vq`.\n///\n/// This is in order to enable calling code to distinguish\n/// between the two cases of the enum. Esp. in some cases\n/// the decoder might have to reject packages with the\n/// NoVqLookupForCodebook variant, but have to treat EndOfPacket\n/// as normal occurence.\npub(crate) enum HuffmanVqReadErr {\n\tEndOfPacket,\n\tNoVqLookupForCodebook,\n}\n\nimpl <'a> BitpackCursor <'a> {\n\t/// Reads a huffman word using the codebook abstraction via a VQ context\n\tpub(crate) fn read_huffman_vq<'b>(&mut self, b :&'b Codebook) -> Result<&'b[f32], HuffmanVqReadErr> {\n\n\t\tlet idx = match self.read_huffman(&b.codebook_huffman_tree) {\n\t\t\tOk(v) => v as usize,\n\t\t\tErr(_) => return Err(HuffmanVqReadErr::EndOfPacket),\n\t\t};\n\t\tlet codebook_vq_lookup_vec :&[f32] = match b.codebook_vq_lookup_vec.as_ref() {\n\t\t\tSome(ref v) => v,\n\t\t\tNone => return Err(HuffmanVqReadErr::NoVqLookupForCodebook),\n\t\t};\n\t\tlet dim = b.codebook_dimensions as usize;\n\t\treturn Ok(&codebook_vq_lookup_vec[idx * dim .. (idx + 1) * dim]);\n\t}\n}\n\nstatic MAX_BASES_WITHOUT_OVERFLOW : &[u32] = &[\n\t0xffffffff, 0xffffffff, 0x0000ffff, 0x00000659,\n\t0x000000ff, 0x00000054, 0x00000028, 0x00000017,\n\t0x0000000f, 0x0000000b, 0x00000009, 0x00000007,\n\t0x00000006, 0x00000005, 0x00000004, 0x00000004,\n\t0x00000003, 0x00000003, 0x00000003, 0x00000003,\n\t0x00000003, 0x00000002, 0x00000002, 0x00000002,\n\t0x00000002, 0x00000002, 0x00000002, 0x00000002,\n\t0x00000002, 0x00000002, 0x00000002, 0x00000002];\n\nstatic MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW : &[u8] = &[\n\t0x1f, 0x1f, 0x0f, 0x0a,\n\t0x07, 0x06, 0x05, 0x04,\n\t0x03, 0x03, 0x03, 0x02,\n\t0x02, 0x02, 0x02, 0x02,\n\t0x01, 0x01, 0x01, 0x01,\n\t0x01, 0x01, 0x01, 0x01,\n\t0x01, 0x01, 0x01, 0x01,\n\t0x01, 0x01, 0x01, 0x01];\n\n// For this little function I won't include the num crate.\n// precondition: base ^ exponent must not overflow.\nfn exp_fast(base :u32, exponent: u8) -> u32 {\n\tlet mut res :u32 = 1;\n\tlet mut selfmul = base;\n\tfor i in 0 .. 8 {\n\t\tif (1 << i) & exponent > 0 {\n\t\t\tres *= selfmul;\n\t\t}\n\t\tif let Some(newselfmul) = u32::checked_mul(selfmul, selfmul) {\n\t\t\tselfmul = newselfmul;\n\t\t} else {\n\t\t\t// Okay, now we have to find out\n\t\t\t// whether this matters or not.\n\t\t\t// Check whether selfmul would have been needed.\n\t\t\tif i < 7 && (exponent >> (i + 1)) > 0 {\n\t\t\t\tpanic!(\"Overflow when squaring for exp_fast, \\\n\t\t\t\t\tprecondition violated!\");\n\t\t\t}\n\t\t\treturn res;\n\t\t}\n\t}\n\treturn res;\n}\n\n/// Returns, as defined in the vorbis spec:\n/// \"the greatest integer for which to `[return_value]` the power of `[codebook_dimensions]` is less than or equal to `[codebook_entries]`\"\n/// Essentially an \"nth-root\" algorithm.\n/// About the speed:\n/// Probably its super-optimized as it uses no floats,\n/// probably smarter algorithms using floats would be faster here. No idea.\n/// Either way, stackoverflow gave the (great) motivation for the algorithm:\n/// http://stackoverflow.com/questions/7407752\nfn lookup1_values(codebook_entries :u32, codebook_dimensions :u16) -> u32 {\n\tif codebook_dimensions >= 32 {\n\t\t// For codebook_dimensions >= 32 we'd already overflow the u32 range if\n\t\t// we computed 2 ^ codebook_dimensions.\n\t\t// Therefore, the result must be less than 2.\n\t\treturn if codebook_entries == 0 { 0 } else { 1 };\n\t}\n\t// Now do a binary search.\n\t// We use two static helper arrays here. Both take the\n\t// exponent (codebook_dimensions here) as index.\n\t// The first array, MAX_BASES_WITHOUT_OVERFLOW contains\n\t// the base that doesn't generate an overflow for the\n\t// given exponent.\n\t// The second array MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW\n\t// contains the number of the highest set bit in\n\t// the corresponding entry in MAX_BASES_WITHOUT_OVERFLOW.\n\t// This is the first bit that is \"disputed\" in the binary\n\t// search to follow: we check the bases to support the\n\t// claim by manual exponentiation.\n\tlet max_base_bits = MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW[\n\t\tcodebook_dimensions as usize];\n\tlet max_base = MAX_BASES_WITHOUT_OVERFLOW[codebook_dimensions as usize];\n\tlet mut base_bits :u32 = 0;\n\tfor i in 0 .. max_base_bits + 1 {\n\t\tlet cur_disputed_bit :u32 = 1 << (max_base_bits - i);\n\t\tbase_bits |= cur_disputed_bit;\n\t\tif max_base < base_bits ||\n\t\t\t\texp_fast(base_bits, codebook_dimensions as u8) > codebook_entries {\n\t\t\tbase_bits &= !cur_disputed_bit;\n\t\t}\n\t}\n\treturn base_bits;\n}\n\n#[test]\nfn test_lookup1_values() {\n\t// First, with base two:\n\t// 2 ^ 10 = 1024\n\tassert_eq!(lookup1_values(1025, 10), 2);\n\tassert_eq!(lookup1_values(1024, 10), 2);\n\tassert_eq!(lookup1_values(1023, 10), 1);\n\n\t// Now, the searched base is five:\n\t// 5 ^ 5 = 3125\n\tassert_eq!(lookup1_values(3126, 5), 5);\n\tassert_eq!(lookup1_values(3125, 5), 5);\n\tassert_eq!(lookup1_values(3124, 5), 4);\n\n\t// Now some exotic tests (edge cases :p):\n\tassert_eq!(lookup1_values(1, 1), 1);\n\tassert_eq!(lookup1_values(0, 15), 0);\n\tassert_eq!(lookup1_values(0, 0), 0);\n\tassert_eq!(lookup1_values(1, 0), std::u32::MAX);\n\tassert_eq!(lookup1_values(400, 0), std::u32::MAX);\n}\n\n/// Reads a codebook which is part of the setup header packet.\nfn read_codebook(rdr :&mut BitpackCursor) -> Result<Codebook, HeaderReadError> {\n\n\t// 1. Read the sync pattern\n\tlet sync_pattern = try!(rdr.read_u24());\n\tif sync_pattern != 0x564342 {\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\n\t// 2. Read the _dimension, _entries fields and the ordered bitflag\n\tlet codebook_dimensions = try!(rdr.read_u16());\n\tlet codebook_entries = try!(rdr.read_u24());\n\tlet ordered = try!(rdr.read_bit_flag());\n\n\t// 3. Read the codeword lengths\n\tlet mut codebook_codeword_lengths = Vec::with_capacity(\n\t\tconvert_to_usize!(codebook_entries, u32));\n\tif !ordered {\n\t\tlet sparse = try!(rdr.read_bit_flag());\n\t\tfor _ in 0 .. codebook_entries {\n\t\t\tlet length = if sparse {\n\t\t\t\tlet flag = try!(rdr.read_bit_flag());\n\t\t\t\tif flag {\n\t\t\t\t\ttry!(rdr.read_u5()) + 1\n\t\t\t\t} else {\n\t\t\t\t\t/* The spec here asks that we should mark that the\n\t\t\t\t\tentry is unused. But 0 already fulfills this purpose,\n\t\t\t\t\tas everywhere else its guaranteed that the length is > 0.\n\t\t\t\t\tNo messing with Option<T> needed here :) */\n\t\t\t\t\t0\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\ttry!(rdr.read_u5()) + 1\n\t\t\t};\n\t\t\tcodebook_codeword_lengths.push(length);\n\t\t}\n\t} else {\n\t\tlet mut current_entry :u32 = 0;\n\t\tlet mut current_length = try!(rdr.read_u5()) + 1;\n\t\twhile current_entry < codebook_entries {\n\t\t\tlet number = try!(rdr.read_dyn_u32(\n\t\t\t\t::ilog((codebook_entries - current_entry) as u64)));\n\t\t\tfor _ in current_entry .. current_entry + number {\n\t\t\t\tcodebook_codeword_lengths.push(current_length);\n\t\t\t}\n\t\t\tcurrent_entry += number;\n\t\t\tcurrent_length += 1;\n\t\t\tif current_entry as u32 > codebook_entries {\n\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t}\n\t\t}\n\t}\n\n\t// 4. Read the vector lookup table\n\tlet codebook_lookup_type = try!(rdr.read_u4());\n\tif codebook_lookup_type > 2 {\n\t\t// Not decodable per vorbis spec\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet codebook_lookup :Option<CodebookVqLookup> =\n\tif codebook_lookup_type == 0 {\n\t\tNone\n\t} else {\n\t\tlet codebook_minimum_value = try!(rdr.read_f32());\n\t\tlet codebook_delta_value = try!(rdr.read_f32());\n\t\tlet codebook_value_bits = try!(rdr.read_u4()) + 1;\n\t\tlet codebook_sequence_p = try!(rdr.read_bit_flag());\n\t\tlet codebook_lookup_values :u64 = if codebook_lookup_type == 1 {\n\t\t\t lookup1_values(codebook_entries, codebook_dimensions) as u64\n\t\t} else {\n\t\t\tcodebook_entries as u64 * codebook_dimensions as u64\n\t\t};\n\t\tlet mut codebook_multiplicands = Vec::with_capacity(\n\t\t\tconvert_to_usize!(codebook_lookup_values, u64));\n\t\tfor _ in 0 .. codebook_lookup_values {\n\t\t\tcodebook_multiplicands.push(try!(rdr.read_dyn_u32(codebook_value_bits)));\n\t\t}\n\t\tSome(CodebookVqLookup {\n\t\t\tcodebook_lookup_type,\n\t\t\tcodebook_minimum_value,\n\t\t\tcodebook_delta_value,\n\t\t\tcodebook_sequence_p,\n\t\t\tcodebook_multiplicands,\n\t\t})\n\t};\n\tlet codebook_vq_lookup_vec = codebook_lookup.as_ref().map(|lup| {\n\t\tlookup_vec_val_decode(lup,\n\t\t\tcodebook_entries, codebook_dimensions)\n\t});\n\n\treturn Ok(Codebook {\n\t\tcodebook_dimensions,\n\t\tcodebook_vq_lookup_vec,\n\t\tcodebook_huffman_tree : try!(VorbisHuffmanTree::load_from_array(&codebook_codeword_lengths)),\n\t});\n}\n\n/// Reads a Floor which is part of the setup header packet.\n/// The `codebook_cnt` param is required to check for compliant streams\nfn read_floor(rdr :&mut BitpackCursor, codebook_cnt :u16, blocksizes :(u8, u8)) ->\n\t\tResult<Floor, HeaderReadError> {\n\tlet floor_type = try!(rdr.read_u16());\n\tmatch floor_type {\n\t\t0 => {\n\t\t\tlet floor0_order = try!(rdr.read_u8());\n\t\t\tlet floor0_rate = try!(rdr.read_u16());\n\t\t\tlet floor0_bark_map_size = try!(rdr.read_u16());\n\t\t\tlet floor0_amplitude_bits = try!(rdr.read_u6());\n\t\t\tif floor0_amplitude_bits > 64 {\n\t\t\t\t// Unfortunately the audio decoder part\n\t\t\t\t// doesn't support values > 64 because rust has no\n\t\t\t\t// 128 bit integers yet.\n\t\t\t\t// TODO when support is added, remove this\n\t\t\t\t// check.\n\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t}\n\t\t\tlet floor0_amplitude_offset = try!(rdr.read_u8());\n\t\t\tlet floor0_number_of_books = try!(rdr.read_u4()) + 1;\n\t\t\tlet mut floor0_book_list = Vec::with_capacity(\n\t\t\t\tconvert_to_usize!(floor0_number_of_books, u8));\n\t\t\tfor _ in 0 .. floor0_number_of_books {\n\t\t\t\tlet value = try!(rdr.read_u8());\n\t\t\t\tif value as u16 > codebook_cnt {\n\t\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t\t}\n\t\t\t\tfloor0_book_list.push(value);\n\t\t\t}\n\t\t\tOk(Floor::TypeZero(FloorTypeZero {\n\t\t\t\tfloor0_order,\n\t\t\t\tfloor0_amplitude_bits,\n\t\t\t\tfloor0_amplitude_offset,\n\t\t\t\tfloor0_number_of_books,\n\t\t\t\tfloor0_book_list,\n\t\t\t\tcached_bark_cos_omega : [\n\t\t\t\t\tcompute_bark_map_cos_omega(1 << (blocksizes.0 - 1),\n\t\t\t\t\t\tfloor0_rate, floor0_bark_map_size),\n\t\t\t\t\tcompute_bark_map_cos_omega(1 << (blocksizes.1 - 1),\n\t\t\t\t\t\tfloor0_rate, floor0_bark_map_size),\n\t\t\t\t]\n\t\t\t}))\n\t\t},\n\t\t1 => {\n\t\t\tlet floor1_partitions = try!(rdr.read_u5());\n\t\t\tlet mut maximum_class :i8 = -1;\n\t\t\tlet mut floor1_partition_class_list = Vec::with_capacity(\n\t\t\t\tfloor1_partitions as usize);\n\t\t\tfor _ in 0 .. floor1_partitions {\n\t\t\t\tlet cur_class = try!(rdr.read_u4());\n\t\t\t\tmaximum_class = if cur_class as i8 > maximum_class\n\t\t\t\t\t{ cur_class as i8 } else { maximum_class };\n\t\t\t\tfloor1_partition_class_list.push(cur_class);\n\t\t\t}\n\n\t\t\t// TODO one day try out whether its more performant\n\t\t\t// to have these two arrays in one, its wasteful to allocate\n\t\t\t// 16 bit so that one can store 5 bits.\n\t\t\tlet mut floor1_class_dimensions = Vec::with_capacity((maximum_class + 1) as usize);\n\t\t\tlet mut floor1_class_subclasses = Vec::with_capacity((maximum_class + 1) as usize);\n\n\t\t\tlet mut floor1_subclass_books = Vec::with_capacity((maximum_class + 1) as usize);\n\n\t\t\tlet mut floor1_class_masterbooks = Vec::with_capacity((maximum_class + 1) as usize);\n\t\t\tfor _ in 0 .. maximum_class + 1 {\n\t\t\t\tfloor1_class_dimensions.push(try!(rdr.read_u3()) + 1);\n\t\t\t\tlet cur_subclass = try!(rdr.read_u2());\n\t\t\t\tfloor1_class_subclasses.push(cur_subclass);\n\t\t\t\tif cur_subclass != 0 {\n\t\t\t\t\tlet cur_masterbook = try!(rdr.read_u8());\n\t\t\t\t\tif cur_masterbook as u16 >= codebook_cnt {\n\t\t\t\t\t\t// undecodable as per spec\n\t\t\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t\t\t}\n\t\t\t\t\tfloor1_class_masterbooks.push(cur_masterbook);\n\t\t\t\t} else {\n\t\t\t\t\t// Some value... This never gets read,\n\t\t\t\t\t// but Rust requires everything to be initialized,\n\t\t\t\t\t// we can't increase the counter without initialisation.\n\t\t\t\t\tfloor1_class_masterbooks.push(0);\n\t\t\t\t}\n\t\t\t\tlet cur_books_cnt :u8 = 1 << cur_subclass;\n\t\t\t\tlet mut cur_books = Vec::with_capacity(cur_books_cnt as usize);\n\t\t\t\tfor _ in 0 .. cur_books_cnt {\n\t\t\t\t\t// The fact that we need i16 here (and shouldn't do\n\t\t\t\t\t// wrapping sub) is only revealed if you read the\n\t\t\t\t\t// \"packet decode\" part of the floor 1 spec...\n\t\t\t\t\tlet cur_book = (try!(rdr.read_u8()) as i16) - 1;\n\t\t\t\t\tif cur_book >= codebook_cnt as i16 {\n\t\t\t\t\t\t// undecodable as per spec\n\t\t\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t\t\t}\n\t\t\t\t\tcur_books.push(cur_book);\n\t\t\t\t}\n\t\t\t\tfloor1_subclass_books.push(cur_books);\n\t\t\t}\n\t\t\tlet floor1_multiplier = try!(rdr.read_u2()) + 1;\n\t\t\tlet rangebits = try!(rdr.read_u4());\n\t\t\tlet mut floor1_values :u16 = 2;\n\t\t\t// Calculate the count before doing anything else\n\t\t\tfor cur_class_num in &floor1_partition_class_list {\n\t\t\t\tfloor1_values += floor1_class_dimensions[*cur_class_num as usize] as u16;\n\t\t\t}\n\t\t\tif floor1_values > 65 {\n\t\t\t\t// undecodable as per spec\n\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t}\n\t\t\tlet mut floor1_x_list = Vec::with_capacity(floor1_values as usize);\n\t\t\tfloor1_x_list.push(0);\n\t\t\tfloor1_x_list.push(1u32 << rangebits);\n\t\t\tfor cur_class_num in &floor1_partition_class_list {\n\t\t\t\tfor _ in 0 .. floor1_class_dimensions[*cur_class_num as usize] {\n\t\t\t\t\tfloor1_x_list.push(try!(rdr.read_dyn_u32(rangebits)));\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Now do an uniqueness check on floor1_x_list\n\t\t\t// to check decodability.\n\t\t\tlet mut floor1_x_list_sorted = floor1_x_list.iter().cloned()\n\t\t\t\t.enumerate().collect::<Vec<_>>();\n\t\t\tfloor1_x_list_sorted.sort_by(|a, b| a.1.cmp(&b.1));\n\t\t\t// 0 is guaranteed to be in the list,\n\t\t\t// and due to sorting it will be first.\n\t\t\tlet mut last = 1;\n\t\t\tfor el in &floor1_x_list_sorted {\n\t\t\t\tif el.1 == last {\n\t\t\t\t\t// duplicate entry found\n\t\t\t\t\t// undecodable as per spec\n\t\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t\t}\n\t\t\t\tlast = el.1;\n\t\t\t}\n\n\t\t\t// Only now return the result\n\t\t\tOk(Floor::TypeOne(FloorTypeOne {\n\t\t\t\tfloor1_multiplier,\n\t\t\t\tfloor1_partition_class : floor1_partition_class_list,\n\t\t\t\tfloor1_class_dimensions,\n\t\t\t\tfloor1_class_subclasses,\n\t\t\t\tfloor1_subclass_books,\n\t\t\t\tfloor1_class_masterbooks,\n\t\t\t\tfloor1_x_list,\n\t\t\t\tfloor1_x_list_sorted,\n\n\t\t\t}))\n\t\t},\n\t\t// Type greater than 1 is error condition per spec\n\t\t_ => Err(HeaderReadError::HeaderBadFormat),\n\t}\n}\n\n/// Reads a Residue which is part of the setup header packet.\n/// The `codebook_cnt` param is required to check for compliant streams\nfn read_residue(rdr :&mut BitpackCursor, codebooks :&[Codebook])\n\t\t-> Result<Residue, HeaderReadError> {\n\tlet residue_type = try!(rdr.read_u16());\n\tif residue_type > 2 {\n\t\t// Undecodable by spec\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet residue_begin = try!(rdr.read_u24());\n\tlet residue_end = try!(rdr.read_u24());\n\tif residue_begin > residue_end {\n\t\t// If residue_begin < residue_end, we'll get\n\t\t// errors in audio parsing code.\n\t\t// As the idea of residue end being before begin\n\t\t// sounds quite wrong anyway, we already error\n\t\t// earlier, in header parsing code.\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet residue_partition_size = try!(rdr.read_u24()) + 1;\n\tlet residue_classifications = try!(rdr.read_u6()) + 1;\n\tlet residue_classbook = try!(rdr.read_u8());\n\t// Read the bitmap pattern:\n\tlet mut residue_cascade = Vec::with_capacity(residue_classifications as usize);\n\tfor _ in 0 .. residue_classifications {\n\t\tlet mut high_bits = 0;\n\t\tlet low_bits = try!(rdr.read_u3());\n\t\tlet bitflag = try!(rdr.read_bit_flag());\n\t\tif bitflag {\n\t\t\thigh_bits = try!(rdr.read_u5());\n\t\t}\n\t\tresidue_cascade.push((high_bits << 3) | low_bits);\n\t}\n\n\tlet mut residue_books = Vec::with_capacity(residue_classifications as usize);\n\t// Read the list of book numbers:\n\tfor cascade_entry in &residue_cascade {\n\t\tresidue_books.push(try!(\n\t\t\tResidueBook::read_book(rdr, *cascade_entry, codebooks)));\n\t}\n\tif residue_classbook as usize >= codebooks.len() {\n\t\t// Undecodable because residue_classbook must be valid index\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\t/*\n\t// Currently we check below condition in audio decode, following the spec,\n\t// section 3.3., saying that it only renders the packet that wants to use the\n\t// invalid codebook invalid, but not the whole stream only because there is a\n\t// residue in the header (which may never be used).\n\tif codebooks[residue_classbook as usize].codebook_vq_lookup_vec.is_none() {\n\t\t// Undecodable because residue_classbook must be valid index\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}*/\n\treturn Ok(Residue {\n\t\tresidue_type : residue_type as u8,\n\t\tresidue_begin,\n\t\tresidue_end,\n\t\tresidue_partition_size,\n\t\tresidue_classifications,\n\t\tresidue_classbook,\n\t\tresidue_books,\n\t});\n}\n\n/// Reads a \"Mapping\" which is part of the setup header packet.\nfn read_mapping(rdr :&mut BitpackCursor,\n\t\taudio_chan_ilog :u8, audio_channels :u8,\n\t\tfloor_count :u8, residue_count :u8)\n\t\t-> Result<Mapping, HeaderReadError> {\n\tlet mapping_type = try!(rdr.read_u16());\n\tif mapping_type > 0 {\n\t\t// Undecodable per spec\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet mapping_submaps = match try!(rdr.read_bit_flag()) {\n\t\ttrue => try!(rdr.read_u4()) + 1,\n\t\tfalse => 1,\n\t};\n\tlet mapping_coupling_steps = match try!(rdr.read_bit_flag()) {\n\t\ttrue => try!(rdr.read_u8()) as u16 + 1,\n\t\tfalse => 0,\n\t};\n\tlet mut mapping_magnitudes = Vec::with_capacity(mapping_coupling_steps as usize);\n\tlet mut mapping_angles = Vec::with_capacity(mapping_coupling_steps as usize);\n\tfor _ in 0 .. mapping_coupling_steps {\n\t\tlet cur_mag = try!(rdr.read_dyn_u8(audio_chan_ilog));\n\t\tlet cur_angle = try!(rdr.read_dyn_u8(audio_chan_ilog));\n\t\tif (cur_angle == cur_mag) || (cur_mag >= audio_channels)\n\t\t\t\t|| (cur_angle >= audio_channels) {\n\t\t\t// Undecodable per spec\n\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t}\n\t\tmapping_magnitudes.push(cur_mag);\n\t\tmapping_angles.push(cur_angle);\n\t}\n\tlet reserved = try!(rdr.read_u2());\n\tif reserved != 0 {\n\t\t// Undecodable per spec\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\tlet mapping_mux = if mapping_submaps > 1 {\n\t\tlet mut m = Vec::with_capacity(audio_channels as usize);\n\t\tfor _ in 0 .. audio_channels {\n\t\t\tlet val = try!(rdr.read_u4());\n\t\t\tif val >= mapping_submaps {\n\t\t\t\t// Undecodable per spec\n\t\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t\t}\n\t\t\tm.push(val);\n\t\t};\n\t\tm\n\t} else {\n\t\tvec![0; audio_channels as usize]\n\t};\n\tlet mut mapping_submap_floors = Vec::with_capacity(mapping_submaps as usize);\n\tlet mut mapping_submap_residues = Vec::with_capacity(mapping_submaps as usize);\n\tfor _ in 0 .. mapping_submaps {\n\t\t// To whom those reserved bits may concern.\n\t\t// I have discarded them!\n\t\ttry!(rdr.read_u8());\n\t\tlet cur_floor = try!(rdr.read_u8());\n\t\tlet cur_residue = try!(rdr.read_u8());\n\t\tif cur_floor >= floor_count ||\n\t\t\t\tcur_residue >= residue_count {\n\t\t\t// Undecodable per spec\n\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t}\n\t\tmapping_submap_floors.push(cur_floor);\n\t\tmapping_submap_residues.push(cur_residue);\n\t}\n\treturn Ok(Mapping {\n\t\tmapping_magnitudes,\n\t\tmapping_angles,\n\t\tmapping_mux,\n\t\tmapping_submap_floors,\n\t\tmapping_submap_residues,\n\t});\n}\n\n/// Reads a ModeInfo which is part of the setup header packet.\nfn read_mode_info(rdr :&mut BitpackCursor, mapping_count :u8) -> Result<ModeInfo, HeaderReadError> {\n\tlet mode_blockflag = try!(rdr.read_bit_flag());\n\tlet mode_windowtype = try!(rdr.read_u16());\n\tlet mode_transformtype = try!(rdr.read_u16());\n\tlet mode_mapping = try!(rdr.read_u8());\n\t// Verifying ranges\n\tif mode_windowtype != 0 ||\n\t\t\tmode_transformtype != 0 ||\n\t\t\tmode_mapping >= mapping_count {\n\t\t// Undecodable per spec\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\treturn Ok(ModeInfo {\n\t\tmode_blockflag,\n\t\tmode_mapping,\n\t});\n}\n\n/// Reading the setup header.\n///\n/// The audio channel and blocksize info needed by the function\n/// can be obtained from the ident header.\npub fn read_header_setup(packet :&[u8], audio_channels :u8, blocksizes :(u8, u8)) ->\n\t\tResult<SetupHeader, HeaderReadError> {\n\tlet mut rdr = BitpackCursor::new(packet);\n\tlet hd_id = try!(read_header_begin(&mut rdr));\n\tif hd_id != 5 {\n\t\ttry!(Err(HeaderReadError::HeaderBadType(hd_id)));\n\t}\n\n\t// Little preparation -- needed later\n\tlet audio_chan_ilog = ::ilog((audio_channels - 1) as u64);\n\n\t//::print_u8_slice(packet);\n\n\t// 1. Read the codebooks\n\tlet vorbis_codebook_count :u16 = try!(rdr.read_u8()) as u16 + 1;\n\tlet mut codebooks = Vec::with_capacity(vorbis_codebook_count as usize);\n\tfor _ in 0 .. vorbis_codebook_count {\n\t\tcodebooks.push(try!(read_codebook(&mut rdr)));\n\t}\n\n\t// 2. Read the time domain transforms\n\tlet vorbis_time_count :u8 = try!(rdr.read_u6()) + 1;\n\tfor _ in 0 .. vorbis_time_count {\n\t\tif try!(rdr.read_u16()) != 0 {\n\t\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t\t}\n\t}\n\n\t// 3. Read the floor values\n\tlet vorbis_floor_count :u8 = try!(rdr.read_u6()) + 1;\n\tlet mut floors = Vec::with_capacity(vorbis_floor_count as usize);\n\tfor _ in 0 .. vorbis_floor_count {\n\t\tfloors.push(try!(read_floor(&mut rdr, vorbis_codebook_count, blocksizes)));\n\t}\n\n\t// 4. Read the residue values\n\tlet vorbis_residue_count :u8 = try!(rdr.read_u6()) + 1;\n\tlet mut residues = Vec::with_capacity(vorbis_residue_count as usize);\n\tfor _ in 0 .. vorbis_residue_count {\n\t\tresidues.push(try!(read_residue(&mut rdr, &codebooks)));\n\t}\n\n\t// 5. Read the mappings\n\tlet vorbis_mapping_count :u8 = try!(rdr.read_u6()) + 1;\n\tlet mut mappings = Vec::with_capacity(vorbis_mapping_count as usize);\n\tfor _ in 0 .. vorbis_mapping_count {\n\t\tmappings.push(try!(read_mapping(& mut rdr,\n\t\t\taudio_chan_ilog, audio_channels,\n\t\t\tvorbis_floor_count, vorbis_residue_count)));\n\t}\n\n\t// 6. Read the modes\n\tlet vorbis_mode_count :u8 = try!(rdr.read_u6()) + 1;\n\tlet mut modes = Vec::with_capacity(vorbis_mode_count as usize);\n\tfor _ in 0 .. vorbis_mode_count {\n\t\tmodes.push(try!(read_mode_info(& mut rdr, vorbis_mapping_count)));\n\t}\n\n\t// Now we only have to make sure the framing bit is set,\n\t// and we can successfully return the setup header!\n\tlet framing :bool = try!(rdr.read_bit_flag());\n\tif !framing {\n\t\ttry!(Err(HeaderReadError::HeaderBadFormat));\n\t}\n\n\treturn Ok(SetupHeader {\n\t\tcodebooks,\n\t\tfloors,\n\t\tresidues,\n\t\tmappings,\n\t\tmodes,\n\t});\n}\n"
  },
  {
    "path": "src/header_cached.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nCached header info\n\nThis mod contains logic to generate and deal with\ndata derived from header information\nthat's used later in the decode process.\n\nThe caching is done to speed up decoding.\n*/\n\n#[derive(Clone)]\npub struct TwiddleFactors {\n\tpub a :Vec<f32>,\n\tpub b :Vec<f32>,\n\tpub c :Vec<f32>,\n}\n\n#[derive(Clone)]\npub struct CachedBlocksizeDerived {\n\tpub twiddle_factors : TwiddleFactors,\n\tpub window_slope : Vec<f32>,\n\tpub bitrev : Vec<u32>,\n}\n\nimpl CachedBlocksizeDerived {\n\tpub fn from_blocksize(bs :u8) -> Self {\n\t\tCachedBlocksizeDerived {\n\t\t\twindow_slope : generate_window((1 << (bs as u16)) >> 1),\n\t\t\ttwiddle_factors : compute_twiddle_factors(bs),\n\t\t\tbitrev : compute_bitreverse(bs),\n\t\t}\n\t}\n}\n\nfn win_slope(x :u16, n :u16) -> f32 {\n\t// please note that there might be a MISTAKE\n\t// in how the spec specifies the right window slope\n\t// function. See \"4.3.1. packet type, mode and window decode\"\n\t// step 7 where it adds an \"extra\" pi/2.\n\t// The left slope doesn't have it, only the right one.\n\t// as stb_vorbis shares the window slope generation function,\n\t// The *other* possible reason is that we don't need the right\n\t// window for anything. TODO investigate this more.\n\tlet v = (0.5 * std::f32::consts::PI * (x as f32 + 0.5) / n as f32).sin();\n\treturn (0.5 * std::f32::consts::PI * v * v ).sin();\n}\n\nfn generate_window(n :u16) -> Vec<f32> {\n\tlet mut window = Vec::with_capacity(n as usize);\n\tfor i in 0 .. n {\n\t\twindow.push(win_slope(i, n));\n\t}\n\treturn window;\n}\n\nfn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors {\n\tlet n = 1 << (blocksize as u16);\n\n\tlet n2 = n >> 1;\n\tlet n4 = n >> 2;\n\tlet n8 = n >> 3;\n\n\tlet mut a = Vec::with_capacity(n2);\n\tlet mut b = Vec::with_capacity(n2);\n\tlet mut c = Vec::with_capacity(n4);\n\n\tlet mut k2 = 0;\n\n\tlet pi_4_n = 4.0 * std::f32::consts::PI / (n as f32);\n\tlet pi_05_n = 0.5 * std::f32::consts::PI / (n as f32);\n\tlet pi_2_n = 2.0 * std::f32::consts::PI / (n as f32);\n\n\tfor k in 0..n4 {\n\t\ta.push( f32::cos((k as f32)      * pi_4_n));\n\t\ta.push(-f32::sin((k as f32)      * pi_4_n));\n\t\tb.push( f32::cos(((k2+1) as f32) * pi_05_n) * 0.5);\n\t\tb.push( f32::sin(((k2+1) as f32) * pi_05_n) * 0.5);\n\t\tk2 += 2;\n\t}\n\tk2 = 0;\n\tfor _ in 0..n8 {\n\t\tc.push( f32::cos(((k2 + 1) as f32) * pi_2_n));\n\t\tc.push(-f32::sin(((k2 + 1) as f32) * pi_2_n));\n\t\tk2 += 2;\n\t}\n\treturn TwiddleFactors {\n\t\ta,\n\t\tb,\n\t\tc,\n\t};\n}\n\nfn compute_bitreverse(blocksize :u8) -> Vec<u32> {\n\tlet ld = blocksize as u16;\n\tlet n = 1 << blocksize;\n\tlet n8 = n >> 3;\n\tlet mut rev = Vec::with_capacity(n8);\n\tfor i in 0 .. n8 {\n\t\trev.push((::bit_reverse(i as u32) as u32 >> (32 - ld + 3)) << 2);\n\t}\n\treturn rev;\n}\n\n#[test]\nfn test_compute_bitreverse() {\n\tlet br = compute_bitreverse(8);\n\t// The output was generated from the output of the\n\t// original stb_vorbis function.\n\tlet cmp_arr = &[\n\t\t0,   64,  32,  96,\n\t\t16,  80,  48, 112,\n\t\t8,   72,  40, 104,\n\t\t24,  88,  56, 120,\n\t\t4,   68,  36, 100,\n\t\t20,  84,  52, 116,\n\t\t12,  76,  44, 108,\n\t\t28,  92,  60, 124];\n\tassert_eq!(br, cmp_arr);\n}\n\n#[inline]\nfn bark(x :f32) -> f32 {\n\t13.1 * (0.00074 * x).atan() + 2.24 * (0.0000000185*x*x).atan() + 0.0001 * x\n}\n\n/// Precomputes bark map values used by floor type 0 packets\n///\n/// Precomputes the cos(omega) values for use by floor type 0 computation.\n///\n/// Note that there is one small difference to the spec: the output\n/// vec is n elements long, not n+1. The last element (at index n)\n/// is -1 in the spec, we lack it. Users of the result of this function\n/// implementation should use it \"virtually\".\npub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16,\n\t\tfloor0_bark_map_size :u16) -> Vec<f32> {\n\tlet mut res = Vec::with_capacity(n as usize);\n\tlet hfl = floor0_rate as f32 / 2.0;\n\tlet hfl_dn = hfl / n as f32;\n\tlet foobar_const_part = floor0_bark_map_size as f32 / bark(hfl);\n\t// Bark map size minus 1:\n\tlet bms_m1 = floor0_bark_map_size as f32 - 1.0;\n\tlet omega_factor = std::f32::consts::PI / floor0_bark_map_size as f32;\n\tfor i in 0 .. n {\n\t\tlet foobar = (bark(i as f32 * hfl_dn) * foobar_const_part).floor();\n\t\tlet map_elem = foobar.min(bms_m1);\n\t\tlet cos_omega = (map_elem * omega_factor).cos();\n\t\tres.push(cos_omega);\n\t}\n\treturn res;\n}\n"
  },
  {
    "path": "src/huffman_tree.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nHuffman tree unpacking and traversal\n\nThis mod contains the `VorbisHuffmanTree` struct which\ncan be loaded from the `codebook_codeword_lengths` array\nspecified for each codebook in the vorbis setup header.\n\nOnce decoding is happening, you are more interested in\nthe `VorbisHuffmanIter` struct which provides you with\nfacilities to load a value bit by bit.\n*/\n\nstruct HuffTree {\n\t// True iff every sub-tree in this tree\n\t// either has two direct children or none\n\teven_childs :bool,\n\tpayload :Option<u32>,\n\tl :Option<Box<HuffTree>>,\n\tr :Option<Box<HuffTree>>,\n}\n\n/*\nuse std::fmt;\nimpl fmt::Debug for HuffTree {\n\tfn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n\t\tfn fmt_rec(s :&HuffTree, f: &mut fmt::Formatter, depth :u32) -> fmt::Result {\n\t\t\tmacro_rules! depth_print {\n\t\t\t($f:ident, $depth:ident) => {\n\t\t\t\tfor _ in 0..$depth {\n\t\t\t\t\ttry!(write!($f, \"| \"));\n\t\t\t\t}\n\t\t\t}}\n\t\t\tif s.l.is_some() || s.r.is_some() {\n\t\t\t\ttry!(writeln!(f, \"ec: {:?}, pl: {:?}, LIS {:?} RIS {:?}\",\n\t\t\t\t\ts.even_childs, s.payload, s.l.is_some(), s.r.is_some()));\n\t\t\t} else {\n\t\t\t\ttry!(writeln!(f, \"ec: {:?}, pl: {:?}\", s.even_childs, s.payload));\n\t\t\t}\n\t\t\tif let Some(ref v) = s.l {\n\t\t\t\tdepth_print!(f, depth);\n\t\t\t\ttry!(write!(f, \"LEFT \"));\n\t\t\t\ttry!(fmt_rec(&*v, f, depth + 1));\n\t\t\t}\n\t\t\tif let Some(ref v) = s.r {\n\t\t\t\tdepth_print!(f, depth);\n\t\t\t\ttry!(write!(f, \"RIGT \"));\n\t\t\t\ttry!(fmt_rec(&*v, f, depth + 1));\n\t\t\t}\n\t\t\treturn Ok(());\n\t\t}\n\t\ttry!(fmt_rec(self, f, 1));\n\t\treturn Ok(());\n\t}\n} // */\n\nimpl HuffTree {\n\t/// Returns whether the addition was successful\n\tpub fn insert_rec(&mut self, payload :u32, depth :u8) -> bool {\n\t\t//print!(\"INSERT payload {:?} depth {:?} \", payload, depth);\n\t\tif self.payload.is_some() {\n\t\t\t//println!(\" => OCCUPIED AS LEAF\");\n\t\t\treturn false;\n\t\t}\n\t\tif depth == 0 {\n\t\t\tif !(self.l.is_none() && self.r.is_none()) {\n\t\t\t\t//println!(\" => INNER NODE\");\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tself.payload = Some(payload);\n\t\t\t//println!(\" => ADDED\");\n\t\t\treturn true;\n\t\t}\n\t\tif self.even_childs {\n\t\t\t//println!(\" => HAS EVEN CHILDS\");\n\t\t\tmatch &mut self.l {\n\t\t\t\t&mut Some(_) => return false,\n\t\t\t\t&mut None => {\n\t\t\t\t\tlet mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None };\n\t\t\t\t\tnew_node.insert_rec(payload, depth - 1);\n\t\t\t\t\tself.l = Some(Box::new(new_node));\n\t\t\t\t\tself.even_childs = false;\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\t//println!(\" => HAS NOT EVEN CHILDS\");\n\t\t\t// First try left branch\n\t\t\tlet left = self.l.as_mut().unwrap();\n\t\t\tif !left.even_childs {\n\t\t\t\tif left.insert_rec(payload, depth - 1) {\n\t\t\t\t\tself.even_childs = left.even_childs &&\n\t\t\t\t\t\tif let &mut Some(ref mut right) = &mut self.r.as_mut() { right.even_childs } else { false };\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// Left sub tree was either full or leaf\n\t\t\t// Therefore, put it in the right branch now\n\t\t\t// As left has even_childs == true, right causes\n\t\t\t// us to have even_childs == false.\n\t\t\treturn match self.r {\n\t\t\t\tSome(ref mut right) => {\n\t\t\t\t\tlet success = right.insert_rec(payload, depth - 1);\n\t\t\t\t\tself.even_childs = left.even_childs && right.even_childs;\n\t\t\t\t\tsuccess\n\t\t\t\t},\n\t\t\t\tNone => {\n\t\t\t\t\tlet mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None };\n\t\t\t\t\tlet success = new_node.insert_rec(payload, depth - 1);\n\t\t\t\t\tself.even_childs = left.even_childs && new_node.even_childs;\n\t\t\t\t\tself.r = Some(Box::new(new_node));\n\t\t\t\t\tsuccess\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t}\n}\n\n#[derive(Debug)]\npub enum HuffmanError {\n\tOverspecified,\n\tUnderpopulated,\n\tInvalidSingleEntry,\n}\n\n#[derive(Clone, Copy)]\nenum UnrolledLookupEntry {\n\t/// The specified entry was found in the lookup array\n\t///\n\t/// First param: offset by which to advance the reader\n\t/// Second param: the payload\n\tHasEntry(u8, u32),\n\t/// Seems the given input is inconclusive and not complete yet.\n\t///\n\t/// The argument contains a hint that is an offset inside desc_prog\n\t/// to help to advance the reader.\n\tInconclusiveWithHint(u32),\n\t/// Seems the given input is inconclusive and not complete yet.\n\tInconclusive,\n}\n\npub enum PeekedDataLookupResult<'l> {\n\t/// The supplied info is not enough to result in a payload directly.\n\t///\n\t/// First param is the number of bits to advance.\n\t///\n\t/// The returned iterator has state up to the count of bits that could be used.\n\tIter(u8, VorbisHuffmanIter<'l>),\n\t/// The supplied info is enough to map to a payload\n\t///\n\t/// First param is the number of bits to advance. Second is payload.\n\tPayloadFound(u8, u32),\n}\n\n/// Huffman tree representation\n#[derive(Clone)]\npub struct VorbisHuffmanTree {\n\t// Format: three bytes per non leaf node, one byte per leaf node.\n\t// First byte is the payload container,\n\t// second and third point to the indices inside the vector that\n\t// have left and right children.\n\t// If the node is a leaf the highest bit of the payload container 0,\n\t// if it has children the bit is 1. If its a leaf the lower 31 bits of the\n\t// payload container form the actual payload.\n\tdesc_prog :Vec<u32>,\n\n\tunrolled_entries :[UnrolledLookupEntry; 256],\n}\n\nimpl VorbisHuffmanTree {\n\t/// Constructs a new `VorbisHuffmanTree` instance from the passed array,\n\t/// like the vorbis spec demands.\n\t///\n\t/// Returns the resulting tree if the array results in a valid (neither\n\t/// underspecified nor overspecified) tree.\n\tpub fn load_from_array(codebook_codeword_lengths :&[u8]) -> Result<VorbisHuffmanTree, HuffmanError> {\n\t\t// First step: generate a simple tree representing the\n\t\t// Huffman tree\n\t\tlet mut simple_tree = HuffTree { even_childs :true, payload :None, l :None, r :None };\n\t\tlet mut cnt :usize = 0;\n\t\tlet mut last_valid_idx = None;\n\t\tfor (i, &codeword_length) in codebook_codeword_lengths.iter().enumerate() {\n\t\t\tif codeword_length == 0 {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcnt += 1;\n\t\t\tlast_valid_idx = Some(i);\n\t\t\tif !simple_tree.insert_rec(i as u32, codeword_length) {\n\t\t\t\ttry!(Err(HuffmanError::Overspecified)) /* Overspecified, can't be put into tree */\n\t\t\t}\n\t\t}\n\t\t//println!(\"The tree:\\n{:?}\", simple_tree);\n\n\t\t// Single entry codebook special handling\n\t\tif cnt == 1 {\n\t\t\tlet decoded = last_valid_idx.unwrap();\n\t\t\tlet encoded_len = codebook_codeword_lengths[decoded];\n\t\t\tif encoded_len == 1 {\n\t\t\t\t// Return a vorbis tree that returns decoded for any single bit input\n\t\t\t\treturn Ok(VorbisHuffmanTree {\n\t\t\t\t\tdesc_prog :vec![1u32 << 31, 3, 3, decoded as u32],\n\t\t\t\t\tunrolled_entries :[\n\t\t\t\t\t\tUnrolledLookupEntry::HasEntry(1, decoded as u32); 256\n\t\t\t\t\t],\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\t// Single entry codebooks must have 1 as their only length entry\n\t\t\t\ttry!(Err(HuffmanError::InvalidSingleEntry))\n\t\t\t}\n\t\t}\n\n\t\tif !simple_tree.even_childs {\n\t\t\ttry!(Err(HuffmanError::Underpopulated)); /* Underpopulated */\n\t\t}\n\n\t\t// Second step: generate the actual desc_prog\n\t\t// by pre_order traversal of the tree.\n\t\t//\n\t\t// The general advantage of this approach over one with only the simple tree\n\t\t// is better cache locality and less memory requirements (at least after the\n\t\t// setup with the simple tree).\n\t\tlet mut desc_prog = Vec::with_capacity(cnt);\n\t\tfn traverse(tree :& HuffTree, desc_prog :&mut Vec<u32>) -> u32 {\n\t\t\tlet cur_pos = desc_prog.len() as u32;\n\t\t\tlet has_children = tree.l.is_some() || tree.r.is_some();\n\n\t\t\tlet entry = ((has_children as u32) << 31) | tree.payload.unwrap_or(0);\n\t\t\t//println!(\"push node (w_children : {:?}) at {:?} : {:?}\", has_children, cur_pos, entry);\n\t\t\tdesc_prog.push(entry);\n\n\t\t\tif has_children {\n\t\t\t\tdesc_prog.push(0);\n\t\t\t\tdesc_prog.push(0);\n\t\t\t\tdesc_prog[cur_pos as usize + 1] =\n\t\t\t\t\ttraverse(tree.l.as_ref().unwrap(), desc_prog);\n\t\t\t\t/*println!(\"left child of node {:?}: at {:?}\", cur_pos,\n\t\t\t\t\tdesc_prog[cur_pos as usize + 1]);// */\n\t\t\t\tdesc_prog[cur_pos as usize + 2] =\n\t\t\t\t\ttraverse(tree.r.as_ref().unwrap(), desc_prog);\n\t\t\t\t/*println!(\"right child of node {:?}: at {:?}\", cur_pos,\n\t\t\t\t\tdesc_prog[cur_pos as usize + 2]);// */\n\t\t\t}\n\t\t\treturn cur_pos;\n\t\t}\n\t\tassert_eq!(traverse(&simple_tree, &mut desc_prog), 0);\n\n\t\t// Third step: generate unrolled entries array\n\t\t// Also by pre_order traversal.\n\t\t//\n\t\t// This gives us a speedup over desc_prog as reading the unrolled\n\t\t// entries should involve less branching and less lookups overall.\n\t\tlet mut unrolled_entries = [UnrolledLookupEntry::Inconclusive; 256];\n\t\tfn uroll_traverse(tree :& HuffTree,\n\t\t\t\tunrolled_entries :&mut [UnrolledLookupEntry; 256],\n\t\t\t\tprefix :u32, prefix_idx :u8,\n\t\t\t\tdesc_prog :&[u32], desc_prog_idx :u32) {\n\t\t\tlet has_children = tree.l.is_some() || tree.r.is_some();\n\n\t\t\tif has_children {\n\t\t\t\t// There are children.\n\t\t\t\t// We'd like to recurse deeper. Can we?\n\t\t\t\tif prefix_idx == 8 {\n\t\t\t\t\t// No we can't.\n\t\t\t\t\t// The tree is too deep.\n\t\t\t\t\tunrolled_entries[prefix as usize] =\n\t\t\t\t\t\tUnrolledLookupEntry::InconclusiveWithHint(desc_prog_idx);\n\t\t\t\t} else {\n\t\t\t\t\t// Recurse deeper.\n\t\t\t\t\turoll_traverse(tree.l.as_ref().unwrap(),\n\t\t\t\t\t\tunrolled_entries,\n\t\t\t\t\t\tprefix + (0 << prefix_idx), prefix_idx + 1,\n\t\t\t\t\t\tdesc_prog, desc_prog[desc_prog_idx as usize + 1]);\n\t\t\t\t\turoll_traverse(tree.r.as_ref().unwrap(),\n\t\t\t\t\t\tunrolled_entries,\n\t\t\t\t\t\tprefix + (1 << prefix_idx), prefix_idx + 1,\n\t\t\t\t\t\tdesc_prog, desc_prog[desc_prog_idx as usize + 2]);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No children, fill the entries in the range according to\n\t\t\t\t// the prefix we have.\n\t\t\t\tlet payload = tree.payload.unwrap();\n\t\t\t\tlet it = 1 << prefix_idx;\n\t\t\t\tlet mut i = prefix as usize;\n\t\t\t\tfor _ in 1 .. (1u16 << (8 - prefix_idx)) {\n\t\t\t\t\tunrolled_entries[i] =\n\t\t\t\t\t\tUnrolledLookupEntry::HasEntry(prefix_idx, payload);\n\t\t\t\t\ti += it;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif cnt > 0 {\n\t\t\turoll_traverse(&simple_tree,\n\t\t\t\t&mut unrolled_entries, 0, 0, &desc_prog, 0);\n\t\t}\n\n\t\t// Now we are done, return the result\n\t\treturn Ok(VorbisHuffmanTree {\n\t\t\tdesc_prog,\n\t\t\tunrolled_entries,\n\t\t});\n\t}\n\n\t/// Returns an iterator over this tree.\n\tpub fn iter<'l>(&'l self) -> VorbisHuffmanIter<'l> {\n\t\treturn VorbisHuffmanIter { desc_prog :&self.desc_prog, pos :0 };\n\t}\n\n\t/// Resolves a given number of peeked bits.\n\t///\n\t/// Returns whether the data given is enough to uniquely identify a\n\t/// tree element, or whether only an iterator that's progressed by\n\t/// a given amount can be returned. Also, info is returned about how\n\t/// far the reader can be advanced.\n\tpub fn lookup_peeked_data<'l>(&'l self, bit_count :u8, peeked_data :u32)\n\t\t\t-> PeekedDataLookupResult<'l> {\n\t\tif bit_count > 8 {\n\t\t\tpanic!(\"Bit count {} larger than allowed 8\", bit_count);\n\t\t}\n\t\tuse self::UnrolledLookupEntry::*;\n\t\tuse self::PeekedDataLookupResult::*;\n\t\treturn match self.unrolled_entries[peeked_data as usize] {\n\t\t\t// If cnt_to_remove is bigger than bit_count the result is inconclusive.\n\t\t\t// Return in this case.\n\t\t\tHasEntry(cnt_to_remove, payload) if cnt_to_remove <= bit_count\n\t\t\t\t=> PayloadFound(cnt_to_remove, payload),\n\t\t\tInconclusiveWithHint(hint)\n\t\t\t\t=> Iter(8, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : hint }),\n\t\t\t_\n\t\t\t\t=> Iter(0, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : 0 }),\n\t\t};\n\t}\n}\n\n/// Iterator on the Huffman tree\npub struct VorbisHuffmanIter<'a> {\n\tdesc_prog :&'a Vec<u32>,\n\tpos :u32,\n}\n\nimpl<'a> VorbisHuffmanIter<'a> {\n\t/// Iterate one level deeper inside the tree.\n\t/// Returns `Some(p)` if it encounters a leaf with a payload p,\n\t/// None if it only processed an inner node.\n\t///\n\t/// Inner nodes don't carry payloads in huffman trees.\n\t///\n\t/// If this function encounters a leaf, it automatically resets\n\t/// the iterator to its starting state.\n\t///\n\t/// # Panics\n\t///\n\t/// Panics if the vorbis huffman treee is empty. It has to be found out\n\t/// what to do if the huffman tree is empty, whether to reject the stream,\n\t/// or whether to do sth else. Finding this out is a TODO.\n\tpub fn next(&mut self, bit :bool) -> Option<u32> {\n\t\t// Assertion test for the paranoid and testing, comment out if you are:\n\t\t/*let cur_entry = self.desc_prog[self.pos as usize];\n\t\tassert!((cur_entry & (1u32 << 31)) != 0);*/\n\n\t\t//print!(\"With bit {:?}, pos {:?} becomes pos \", bit, self.pos);\n\t\tself.pos = self.desc_prog[self.pos as usize + 1 + bit as usize];\n\t\t//print!(\"{:?}\", self.pos);\n\t\tlet child = self.desc_prog[self.pos as usize];\n\t\tif (child & (1u32 << 31)) != 0 {\n\t\t\t//println!(\" => None\");\n\t\t\t// child has children\n\t\t\treturn None;\n\t\t} else {\n\t\t\t//println!(\" => Some({:?})\", child);\n\t\t\t// child has no children, it's a leaf\n\t\t\tself.pos = 0;\n\t\t\treturn Some(child);\n\t\t}\n\t}\n}\n\n#[cfg(test)]\nimpl VorbisHuffmanTree {\n\tfn iter_test(&self, path :u32, path_len :u8, expected_val :u32) {\n\t\tlet mut itr = self.iter();\n\t\tfor i in 1 .. path_len {\n\t\t\tassert_eq!(itr.next((path & (1 << (path_len - i))) != 0), None);\n\t\t}\n\t\tassert_eq!(itr.next((path & 1) != 0), Some(expected_val));\n\t}\n}\n\n#[test]\nfn test_huffman_tree() {\n\t// Official example from the vorbis spec section 3.2.1\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3]).unwrap();\n\n\ttree.iter_test(0b00, 2, 0);\n\ttree.iter_test(0b0100, 4, 1);\n\ttree.iter_test(0b0101, 4, 2);\n\ttree.iter_test(0b0110, 4, 3);\n\ttree.iter_test(0b0111, 4, 4);\n\ttree.iter_test(0b10, 2, 5);\n\ttree.iter_test(0b110, 3, 6);\n\ttree.iter_test(0b111, 3, 7);\n\n\t// Some other example\n\t// we mostly test the length (max 32) here\n\tVorbisHuffmanTree::load_from_array(&[\n\t\t1,   2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,\n\t\t17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32]).unwrap();\n}\n\n#[test]\nfn test_issue_8() {\n\t// regression test for issue 8\n\t// make sure that it doesn't panic.\n\tlet _ = VorbisHuffmanTree::load_from_array(&[0; 625]);\n}\n\n#[test]\nfn test_under_over_spec() {\n\t// All trees base on the official example from the vorbis spec section 3.2.1\n\t// but with modifications to under- or overspecify them\n\n\t// underspecified\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3/*, 3*/]);\n\tassert!(tree.is_err());\n\n\t// underspecified\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, /*4,*/ 2, 3, 3]);\n\tassert!(tree.is_err());\n\n\t// overspecified\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3/*]*/,3]);\n\tassert!(tree.is_err());\n}\n\n#[test]\nfn test_single_entry_huffman_tree() {\n\t// Special testing for single entry codebooks, as required by the vorbis spec\n\tlet tree = VorbisHuffmanTree::load_from_array(&[1]).unwrap();\n\ttree.iter_test(0b0, 1, 0);\n\ttree.iter_test(0b1, 1, 0);\n\n\tlet tree = VorbisHuffmanTree::load_from_array(&[0, 0, 1, 0]).unwrap();\n\ttree.iter_test(0b0, 1, 2);\n\ttree.iter_test(0b1, 1, 2);\n\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2]);\n\tassert!(tree.is_err());\n}\n\n#[test]\nfn test_unordered_huffman_tree() {\n\t// Reordered the official example from the vorbis spec section 3.2.1\n\t//\n\t// Ensuring that unordered huffman trees work as well is important\n\t// because the spec does not disallow them, and unordered\n\t// huffman trees appear in \"the wild\".\n\tlet tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 2, 4, 4, 3, 3]).unwrap();\n\n\ttree.iter_test(0b00, 2, 0);\n\ttree.iter_test(0b0100, 4, 1);\n\ttree.iter_test(0b0101, 4, 2);\n\ttree.iter_test(0b10, 2, 3);\n\ttree.iter_test(0b0110, 4, 4);\n\ttree.iter_test(0b0111, 4, 5);\n\ttree.iter_test(0b110, 3, 6);\n\ttree.iter_test(0b111, 3, 7);\n}\n\n#[test]\nfn test_extracted_huffman_tree() {\n\t// Extracted from a real-life vorbis file.\n\tVorbisHuffmanTree::load_from_array(&[\n\t5,  6, 11, 11, 11, 11, 10, 10, 12, 11,  5,  2, 11,  5,  6,  6,\n\t7,  9, 11, 13, 13, 10,  7, 11,  6,  7,  8,  9, 10, 12, 11,  5,\n\t11, 6,  8,  7,  9, 11, 14, 15, 11,  6,  6,  8,  4,  5,  7,  8,\n\t10,13, 10,  5,  7,  7,  5,  5,  6,  8, 10, 11, 10,  7,  7,  8,\n\t6,  5,  5,  7,  9,  9, 11,  8,  8, 11,  8,  7,  6,  6,  7,  9,\n\t12,11, 10, 13,  9,  9,  7,  7,  7,  9, 11, 13, 12, 15, 12, 11,\n\t9,  8,  8,  8]).unwrap();\n}\n"
  },
  {
    "path": "src/imdct.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n// This file is a very close translation of the\n// implementation of the algorithm from stb_vorbis.\n\nuse ::header_cached::CachedBlocksizeDerived;\n\nfn imdct_step3_iter0_loop(n :usize, e :&mut[f32], i_off :usize, k_off :isize, a :&[f32]) {\n\tlet mut a_offs = 0;\n\tlet mut i_offs = i_off;\n\tlet mut k_offs = i_off as isize + k_off;\n\n\tmacro_rules! ee0 {\n\t\t(-$x:expr) => {e[i_offs - ($x as usize)]};\n\t\t($x:expr) => {e[i_offs + ($x as usize)]}\n\t}\n\n\tmacro_rules! ee2 {\n\t\t(-$x:expr) => {e[(k_offs - $x) as usize]};\n\t\t($x:expr) => {e[(k_offs + $x) as usize]}\n\t}\n\n\tmacro_rules! aa {\n\t\t($x:expr) => {a[a_offs + ($x as usize)]}\n\t}\n\n\tassert_eq!((n & 3), 0);\n\n\tfor _ in 0 .. n >> 2 {\n\t\tlet mut k00_20 = ee0![ 0] - ee2![ 0];\n\t\tlet mut k01_21 = ee0![-1] - ee2![-1];\n\t\tee0![ 0] += ee2![ 0];\n\t\tee0![-1] += ee2![-1];\n\t\tee2![ 0] = k00_20 * aa![0] - k01_21 * aa![1];\n\t\tee2![-1] = k01_21 * aa![0] + k00_20 * aa![1];\n\t\ta_offs += 8;\n\n\t\tk00_20  = ee0![-2] - ee2![-2];\n\t\tk01_21  = ee0![-3] - ee2![-3];\n\t\tee0![-2] += ee2![-2];\n\t\tee0![-3] += ee2![-3];\n\t\tee2![-2] = k00_20 * aa![0] - k01_21 * aa![1];\n\t\tee2![-3] = k01_21 * aa![0] + k00_20 * aa![1];\n\t\ta_offs += 8;\n\n\t\tk00_20  = ee0![-4] - ee2![-4];\n\t\tk01_21  = ee0![-5] - ee2![-5];\n\t\tee0![-4] += ee2![-4];\n\t\tee0![-5] += ee2![-5];\n\t\tee2![-4] = k00_20 * aa![0] - k01_21 * aa![1];\n\t\tee2![-5] = k01_21 * aa![0] + k00_20 * aa![1];\n\t\ta_offs += 8;\n\n\t\tk00_20  = ee0![-6] - ee2![-6];\n\t\tk01_21  = ee0![-7] - ee2![-7];\n\t\tee0![-6] += ee2![-6];\n\t\tee0![-7] += ee2![-7];\n\t\tee2![-6] = k00_20 * aa![0] - k01_21 * aa![1];\n\t\tee2![-7] = k01_21 * aa![0] + k00_20 * aa![1];\n\n\t\ta_offs += 8;\n\t\ti_offs -= 8;\n\t\tk_offs -= 8;\n\t}\n}\n\nfn imdct_step3_inner_r_loop(lim :usize, e :&mut [f32],\n\t\td0 :usize, k_off :isize, a :&[f32], k1 :usize) {\n\tlet mut a_offs = 0;\n\tlet mut d0_offs = d0;\n\tlet mut k_offs = d0 as isize + k_off;\n\n\tmacro_rules! e0 {\n\t\t(-$x:expr) => {e[d0_offs - ($x as usize)]};\n\t\t($x:expr) => {e[d0_offs + ($x as usize)]}\n\t}\n\n\tmacro_rules! e2 {\n\t\t(-$x:expr) => {e[(k_offs - $x) as usize]};\n\t\t($x:expr) => {e[(k_offs + $x) as usize]}\n\t}\n\n\tmacro_rules! aa {\n\t\t($x:expr) => {a[a_offs + ($x as usize)]}\n\t}\n\n\tfor _ in 0 .. lim >> 2 {\n\t\tlet mut k00_20 = e0![-0] - e2![-0];\n\t\tlet mut k01_21 = e0![-1] - e2![-1];\n\t\te0![-0] += e2![-0];\n\t\te0![-1] += e2![-1];\n\t\te2![-0] = (k00_20) * aa![0] - (k01_21) * aa![1];\n\t\te2![-1] = (k01_21) * aa![0] + (k00_20) * aa![1];\n\n\t\ta_offs += k1;\n\n\t\tk00_20 = e0![-2] - e2![-2];\n\t\tk01_21 = e0![-3] - e2![-3];\n\t\te0![-2] += e2![-2];\n\t\te0![-3] += e2![-3];\n\t\te2![-2] = (k00_20) * aa![0] - (k01_21) * aa![1];\n\t\te2![-3] = (k01_21) * aa![0] + (k00_20) * aa![1];\n\n\t\ta_offs += k1;\n\n\t\tk00_20 = e0![-4] - e2![-4];\n\t\tk01_21 = e0![-5] - e2![-5];\n\t\te0![-4] += e2![-4];\n\t\te0![-5] += e2![-5];\n\t\te2![-4] = (k00_20) * aa![0] - (k01_21) * aa![1];\n\t\te2![-5] = (k01_21) * aa![0] + (k00_20) * aa![1];\n\n\t\ta_offs += k1;\n\n\t\tk00_20 = e0![-6] - e2![-6];\n\t\tk01_21 = e0![-7] - e2![-7];\n\t\te0![-6] += e2![-6];\n\t\te0![-7] += e2![-7];\n\t\te2![-6] = (k00_20) * aa![0] - (k01_21) * aa![1];\n\t\te2![-7] = (k01_21) * aa![0] + (k00_20) * aa![1];\n\n\t\td0_offs -= 8;\n\t\tk_offs -= 8;\n\n\t\ta_offs += k1;\n\t}\n}\n\nfn imdct_step3_inner_s_loop(n :usize, e :&mut [f32], i_off :usize, k_off :isize,\n\t\ta :&[f32], a_off :usize, k0 :usize) {\n\tlet a0 = a[0];\n\tlet a1 = a[0+1];\n\tlet a2 = a[0+a_off];\n\tlet a3 = a[0+a_off+1];\n\tlet a4 = a[0+a_off*2+0];\n\tlet a5 = a[0+a_off*2+1];\n\tlet a6 = a[0+a_off*3+0];\n\tlet a7 = a[0+a_off*3+1];\n\n\tlet mut i_offs = i_off;\n\tlet mut k_offs = (i_off as isize + k_off) as usize;\n\n\tmacro_rules! ee0 {\n\t\t(-$x:expr) => {e[i_offs - ($x as usize)]};\n\t\t($x:expr) => {e[i_offs + ($x as usize)]}\n\t}\n\n\tmacro_rules! ee2 {\n\t\t(-$x:expr) => {e[k_offs - ($x as usize)]};\n\t\t($x:expr) => {e[k_offs + ($x as usize)]}\n\t}\n\n\tlet mut i = 0;\n\tloop {\n\t\tlet mut k00 = ee0![ 0] - ee2![ 0];\n\t\tlet mut k11 = ee0![-1] - ee2![-1];\n\t\tee0![ 0] =  ee0![ 0] + ee2![ 0];\n\t\tee0![-1] =  ee0![-1] + ee2![-1];\n\t\tee2![ 0] = (k00) * a0 - (k11) * a1;\n\t\tee2![-1] = (k11) * a0 + (k00) * a1;\n\n\t\tk00      = ee0![-2] - ee2![-2];\n\t\tk11      = ee0![-3] - ee2![-3];\n\t\tee0![-2] =  ee0![-2] + ee2![-2];\n\t\tee0![-3] =  ee0![-3] + ee2![-3];\n\t\tee2![-2] = (k00) * a2 - (k11) * a3;\n\t\tee2![-3] = (k11) * a2 + (k00) * a3;\n\n\t\tk00      = ee0![-4] - ee2![-4];\n\t\tk11      = ee0![-5] - ee2![-5];\n\t\tee0![-4] =  ee0![-4] + ee2![-4];\n\t\tee0![-5] =  ee0![-5] + ee2![-5];\n\t\tee2![-4] = (k00) * a4 - (k11) * a5;\n\t\tee2![-5] = (k11) * a4 + (k00) * a5;\n\n\t\tk00      = ee0![-6] - ee2![-6];\n\t\tk11      = ee0![-7] - ee2![-7];\n\t\tee0![-6] =  ee0![-6] + ee2![-6];\n\t\tee0![-7] =  ee0![-7] + ee2![-7];\n\t\tee2![-6] = (k00) * a6 - (k11) * a7;\n\t\tee2![-7] = (k11) * a6 + (k00) * a7;\n\n\t\ti += 1;\n\t\t// we have this check instead of a for loop\n\t\t// over an iterator because otherwise we\n\t\t// overflow.\n\t\tif i >= n {\n\t\t\tbreak;\n\t\t}\n\t\ti_offs -= k0;\n\t\tk_offs -= k0;\n\t}\n}\n\n#[inline]\nfn iter_54(zm7 :&mut [f32]) {\n\t// difference from stb_vorbis implementation:\n\t// zm7 points to z minus 7\n\t// (Rust disallows negative indices)\n\n\tlet k00  = zm7[7] - zm7[3];\n\tlet y0   = zm7[7] + zm7[3];\n\tlet y2   = zm7[5] + zm7[1];\n\tlet k22  = zm7[5] - zm7[1];\n\n\tzm7[7] = y0 + y2;      // z0 + z4 + z2 + z6\n\tzm7[5] = y0 - y2;      // z0 + z4 - z2 - z6\n\n\t// done with y0,y2\n\n\tlet k33  = zm7[4] - zm7[0];\n\n\tzm7[3] = k00 + k33;    // z0 - z4 + z3 - z7\n\tzm7[1] = k00 - k33;    // z0 - z4 - z3 + z7\n\n\t// done with k33\n\n\tlet k11  = zm7[6] - zm7[2];\n\tlet y1   = zm7[6] + zm7[2];\n\tlet y3   = zm7[4] + zm7[0];\n\n\tzm7[6] = y1 + y3;      // z1 + z5 + z3 + z7\n\tzm7[4] = y1 - y3;      // z1 + z5 - z3 - z7\n\tzm7[2] = k11 - k22;    // z1 - z5 + z2 - z6\n\tzm7[0] = k11 + k22;    // z1 - z5 - z2 + z6\n}\n\nfn imdct_step3_inner_s_loop_ld654(n :usize, e :&mut [f32], i_off :usize,\n\ta :&[f32], base_n :usize)\n{\n\tlet a_off = base_n >> 3;\n\tlet a2 = a[a_off];\n\n\tlet mut z_offs = i_off;\n\n\tlet basep16 = i_off - 16 * (n - 1 as usize);\n\n\tmacro_rules! z {\n\t\t(-$x:expr) => {e[z_offs - ($x as usize)]}\n\t}\n\n\tloop {\n\t\tlet mut k00 = z![-0] - z![-8];\n\t\tlet mut k11 = z![-1] - z![-9];\n\t\tz![-0] = z![-0] + z![-8];\n\t\tz![-1] = z![-1] + z![-9];\n\t\tz![-8] =  k00;\n\t\tz![-9] =  k11;\n\n\t\tk00     = z![ -2] - z![-10];\n\t\tk11     = z![ -3] - z![-11];\n\t\tz![ -2] = z![ -2] + z![-10];\n\t\tz![ -3] = z![ -3] + z![-11];\n\t\tz![-10] = (k00+k11) * a2;\n\t\tz![-11] = (k11-k00) * a2;\n\n\t\tk00     = z![-12] - z![ -4];  // reverse to avoid a unary negation\n\t\tk11     = z![ -5] - z![-13];\n\t\tz![ -4] = z![ -4] + z![-12];\n\t\tz![ -5] = z![ -5] + z![-13];\n\t\tz![-12] = k11;\n\t\tz![-13] = k00;\n\n\t\tk00     = z![-14] - z![ -6];  // reverse to avoid a unary negation\n\t\tk11     = z![ -7] - z![-15];\n\t\tz![ -6] = z![ -6] + z![-14];\n\t\tz![ -7] = z![ -7] + z![-15];\n\t\tz![-14] = (k00+k11) * a2;\n\t\tz![-15] = (k00-k11) * a2;\n\n\t\titer_54(e.split_at_mut(z_offs - 7).1);\n\t\titer_54(e.split_at_mut(z_offs - 7 - 8).1);\n\t\t// We need to compare with basep16 here\n\t\t// in order to prevent a possible overflow\n\t\t// in calculation of base, and in calculation\n\t\t// of z_offs.\n\t\tif z_offs <= basep16 {\n\t\t\tbreak;\n\t\t}\n\t\tz_offs -= 16;\n\t}\n}\n\n#[allow(dead_code)]\npub fn inverse_mdct(cached_bd :&CachedBlocksizeDerived, buffer :&mut [f32], bs :u8) {\n\tlet n = buffer.len();\n\t// Pre-condition.\n\tassert_eq!(n, 1 << bs);\n\n\tlet n2 = n >> 1;\n\tlet n4 = n >> 2;\n\tlet n8 = n >> 3;\n\n\t// TODO later on we might want to do Vec::with_capacity here,\n\t// and use buf2.push everywhere...\n\tlet mut buf2 :Vec<f32> = vec![0.0; n2];\n\n\tlet ctf = &cached_bd.twiddle_factors;\n\tlet a :&[f32] = &ctf.a;\n\tlet b :&[f32] = &ctf.b;\n\tlet c :&[f32] = &ctf.c;\n\n\tmacro_rules! break_if_sub_overflows {\n\t\t($i:ident, $x:expr) => {\n\t\t\t$i = match $i.checked_sub($x) {\n\t\t\t\tSome(v) => v,\n\t\t\t\tNone => break,\n\t\t\t};\n\t\t}\n\t}\n\n\t// IMDCT algorithm from \"The use of multirate filter banks for coding of high quality digital audio\"\n\t// See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' in stb_vorbis original.\n\n\t// kernel from paper\n\n\n\t// merged:\n\t//   copy and reflect spectral data\n\t//   step 0\n\n\t// note that it turns out that the items added together during\n\t// this step are, in fact, being added to themselves (as reflected\n\t// by step 0). inexplicable inefficiency! this became obvious\n\t// once I combined the passes.\n\n\t// so there's a missing 'times 2' here (for adding X to itself).\n\t// this propogates through linearly to the end, where the numbers\n\t// are 1/2 too small, and need to be compensated for.\n\n\t{\n\t\tlet mut a_offs = 0;\n\t\tlet mut d_offs = n2 - 2;\n\t\tlet mut e_offs = 0;\n\t\tlet e_stop = n2;\n\n\t\tmacro_rules! d {\n\t\t\t($x:expr) => {buf2[d_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! aa {\n\t\t\t($x:expr) => {a[a_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! e {\n\t\t\t($x:expr) => {buffer[e_offs + ($x as usize)]}\n\t\t}\n\n\t\t// TODO replace the while with a for once step_by on iterators\n\t\t// is stabilized\n\t\twhile e_offs != e_stop {\n\t\t\td![1] = e![0] * aa![0] - e![2]*aa![1];\n\t\t\td![0] = e![0] * aa![1] + e![2]*aa![0];\n\t\t\td_offs -= 2;\n\t\t\ta_offs += 2;\n\t\t\te_offs += 4;\n\t\t}\n\n\t\te_offs = n2 - 3;\n\t\tloop {\n\t\t\td![1] = -e![2] * aa![0] - -e![0]*aa![1];\n\t\t\td![0] = -e![2] * aa![1] + -e![0]*aa![0];\n\t\t\tbreak_if_sub_overflows!(d_offs, 2);\n\t\t\ta_offs += 2;\n\t\t\te_offs -= 4;\n\t\t}\n\t}\n\n\n\t{\n\t\t// now we use symbolic names for these, so that we can\n\t\t// possibly swap their meaning as we change which operations\n\t\t// are in place\n\n\t\tlet u = &mut *buffer;\n\t\tlet v = &mut *buf2;\n\n\t\t// step 2    (paper output is w, now u)\n\t\t// this could be in place, but the data ends up in the wrong\n\t\t// place... _somebody_'s got to swap it, so this is nominated\n\t\t{\n\t\t\tlet mut a_offs = n2 - 8;\n\t\t\tlet mut d0_offs = n4;\n\t\t\tlet mut d1_offs = 0;\n\t\t\tlet mut e0_offs = n4;\n\t\t\tlet mut e1_offs = 0;\n\n\t\t\tmacro_rules! aa {\n\t\t\t\t($x:expr) => {a[a_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! d0 {\n\t\t\t\t($x:expr) => {u[d0_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! d1 {\n\t\t\t\t($x:expr) => {u[d1_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! e0 {\n\t\t\t\t($x:expr) => {v[e0_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! e1 {\n\t\t\t\t($x:expr) => {v[e1_offs + ($x as usize)]}\n\t\t\t}\n\n\t\t\tloop {\n\t\t\t\tlet mut v41_21 = e0![1] - e1![1];\n\t\t\t\tlet mut v40_20 = e0![0] - e1![0];\n\t\t\t\td0![1]  = e0![1] + e1![1];\n\t\t\t\td0![0]  = e0![0] + e1![0];\n\t\t\t\td1![1]  = v41_21*aa![4] - v40_20*aa![5];\n\t\t\t\td1![0]  = v40_20*aa![4] + v41_21*aa![5];\n\n\t\t\t\tv41_21 = e0![3] - e1![3];\n\t\t\t\tv40_20 = e0![2] - e1![2];\n\t\t\t\td0![3]  = e0![3] + e1![3];\n\t\t\t\td0![2]  = e0![2] + e1![2];\n\t\t\t\td1![3]  = v41_21*aa![0] - v40_20*aa![1];\n\t\t\t\td1![2]  = v40_20*aa![0] + v41_21*aa![1];\n\n\t\t\t\tbreak_if_sub_overflows!(a_offs, 8);\n\n\t\t\t\td0_offs += 4;\n\t\t\t\td1_offs += 4;\n\t\t\t\te0_offs += 4;\n\t\t\t\te1_offs += 4;\n\t\t\t}\n\t\t}\n\n\n\t\t// step 3\n\n\t\tlet ld = bs as usize;\n\n\t\t// optimized step 3:\n\n\t\t// the original step3 loop can be nested r inside s or s inside r;\n\t\t// it's written originally as s inside r, but this is dumb when r\n\t\t// iterates many times, and s few. So I have two copies of it and\n\t\t// switch between them halfway.\n\n\t\t// this is iteration 0 of step 3\n\t\timdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n as isize >> 3), a);\n\t\timdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n as isize >> 3), a);\n\n\t\t// this is iteration 1 of step 3\n\t\timdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n as isize >> 4), a, 16);\n\t\timdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n as isize >> 4), a, 16);\n\t\timdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n as isize >> 4), a, 16);\n\t\timdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n as isize >> 4), a, 16);\n\n\t\tfor l in 2 .. (ld - 3) >> 1 {\n\t\t\tlet k0 = n >> (l + 2);\n\t\t\tlet k0_2 = k0 as isize >> 1;\n\t\t\tlet lim = 1 << (l+1);\n\t\t\tfor i in 0 .. lim {\n\t\t\t\timdct_step3_inner_r_loop(n >> (l + 4),\n\t\t\t\t\tu, n2-1 - k0*i, -k0_2, a, 1 << (l+3));\n\t\t\t}\n\t\t}\n\t\tfor l in (ld - 3) >> 1 .. ld - 6 {\n\t\t\tlet k0 = n >> (l + 2);\n\t\t\tlet k1 = 1 << (l + 3);\n\t\t\tlet k0_2 = k0 as isize >> 1;\n\t\t\tlet rlim = n >> (l + 6);\n\t\t\tlet lim = 1 << (l + 1);\n\t\t\tlet mut i_off = n2 - 1;\n\t\t\tlet mut a_off = 0;\n\t\t\tfor _ in 0 .. rlim {\n\t\t\t\tlet a0 = a.split_at(a_off).1;\n\t\t\t\timdct_step3_inner_s_loop(lim, u, i_off, -k0_2, a0, k1, k0);\n\t\t\t\ta_off += k1 * 4;\n\t\t\t\ti_off -= 8;\n\t\t\t}\n\t\t}\n\n\t\t// iterations with count:\n\t\t//   ld-6,-5,-4 all interleaved together\n\t\t//       the big win comes from getting rid of needless flops\n\t\t//         due to the constants on pass 5 & 4 being all 1 and 0;\n\t\t//       combining them to be simultaneous to improve cache made little difference\n\t\timdct_step3_inner_s_loop_ld654(n >> 5, u, n2 - 1, a, n);\n\n\t\t// output is u\n\n\t\t// step 4, 5, and 6\n\t\t// cannot be in-place because of step 5\n\t\t{\n\t\t\tlet bitrev_vec = &cached_bd.bitrev;\n\t\t\t// weirdly, I'd have thought reading sequentially and writing\n\t\t\t// erratically would have been better than vice-versa, but in\n\t\t\t// fact that's not what my testing showed. (That is, with\n\t\t\t// j = bitreverse(i), do you read i and write j, or read j and write i.)\n\n\t\t\tlet mut d0_offs = n4 - 4;\n\t\t\tlet mut d1_offs = n2 - 4;\n\t\t\tlet mut bitrev_offs = 0;\n\n\t\t\tmacro_rules! d0 {\n\t\t\t\t($x:expr) => {v[d0_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! d1 {\n\t\t\t\t($x:expr) => {v[d1_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! bitrev {\n\t\t\t\t($x:expr) => {bitrev_vec[bitrev_offs + ($x as usize)]}\n\t\t\t}\n\n\t\t\tloop {\n\t\t\t\tlet mut k4 = bitrev![0] as usize;\n\t\t\t\td1![3] = u[k4 + 0];\n\t\t\t\td1![2] = u[k4 + 1];\n\t\t\t\td0![3] = u[k4 + 2];\n\t\t\t\td0![2] = u[k4 + 3];\n\n\t\t\t\tk4 = bitrev![1] as usize;\n\t\t\t\td1![1] = u[k4 + 0];\n\t\t\t\td1![0] = u[k4 + 1];\n\t\t\t\td0![1] = u[k4 + 2];\n\t\t\t\td0![0] = u[k4 + 3];\n\n\t\t\t\tbreak_if_sub_overflows!(d0_offs, 4);\n\t\t\t\td1_offs -= 4;\n\t\t\t\tbitrev_offs += 2;\n\t\t\t}\n\t\t}\n\t\t// (paper output is u, now v)\n\n\t\t// step 7   (paper output is v, now v)\n\t\t// this is now in place\n\t\t{\n\t\t\tlet mut c_offs = 0;\n\t\t\tlet mut d_offs = 0;\n\t\t\tlet mut e_offs = n2 - 4;\n\n\t\t\tmacro_rules! cc {\n\t\t\t\t($x:expr) => {c[c_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! d {\n\t\t\t\t($x:expr) => {v[d_offs + ($x as usize)]}\n\t\t\t}\n\t\t\tmacro_rules! e {\n\t\t\t\t($x:expr) => {v[e_offs + ($x as usize)]}\n\t\t\t}\n\t\t\twhile d_offs < e_offs {\n\t\t\t\tlet mut a02 = d![0] - e![2];\n\t\t\t\tlet mut a11 = d![1] + e![3];\n\n\t\t\t\tlet mut b0 = cc![1]*a02 + cc![0]*a11;\n\t\t\t\tlet mut b1 = cc![1]*a11 - cc![0]*a02;\n\n\t\t\t\tlet mut b2 = d![0] + e![ 2];\n\t\t\t\tlet mut b3 = d![1] - e![ 3];\n\n\t\t\t\td![0] = b2 + b0;\n\t\t\t\td![1] = b3 + b1;\n\t\t\t\te![2] = b2 - b0;\n\t\t\t\te![3] = b1 - b3;\n\n\t\t\t\ta02 = d![2] - e![0];\n\t\t\t\ta11 = d![3] + e![1];\n\n\t\t\t\tb0 = cc![3]*a02 + cc![2]*a11;\n\t\t\t\tb1 = cc![3]*a11 - cc![2]*a02;\n\n\t\t\t\tb2 = d![2] + e![ 0];\n\t\t\t\tb3 = d![3] - e![ 1];\n\n\t\t\t\td![2] = b2 + b0;\n\t\t\t\td![3] = b3 + b1;\n\t\t\t\te![0] = b2 - b0;\n\t\t\t\te![1] = b1 - b3;\n\n\t\t\t\tc_offs += 4;\n\t\t\t\td_offs += 4;\n\t\t\t\te_offs -= 4;\n\t\t\t}\n\t\t}\n\t}\n\n\t// step 8+decode   (paper output is X, now buffer)\n\t// this generates pairs of data a la 8 and pushes them directly through\n\t// the decode kernel (pushing rather than pulling) to avoid having\n\t// to make another pass later\n\n\t// this cannot POSSIBLY be in place, so we refer to the buffers directly\n\t{\n\t\tlet mut d0_offs = 0;\n\t\tlet mut d1_offs = n2 - 4;\n\t\tlet mut d2_offs = n2;\n\t\tlet mut d3_offs = n - 4;\n\n\t\tlet mut b_offs = n2 - 8;\n\t\tlet mut e_offs = n2 - 8;\n\n\t\tmacro_rules! d0 {\n\t\t\t($x:expr) => {buffer[d0_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! d1 {\n\t\t\t($x:expr) => {buffer[d1_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! d2 {\n\t\t\t($x:expr) => {buffer[d2_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! d3 {\n\t\t\t($x:expr) => {buffer[d3_offs + ($x as usize)]}\n\t\t}\n\n\t\tmacro_rules! b {\n\t\t\t($x:expr) => {b[b_offs + ($x as usize)]}\n\t\t}\n\t\tmacro_rules! e {\n\t\t\t($x:expr) => {buf2[e_offs + ($x as usize)]}\n\t\t}\n\n\t\tloop {\n\t\t\tlet mut p3 =  e![6]*b![7] - e![7]*b![6];\n\t\t\tlet mut p2 = -e![6]*b![6] - e![7]*b![7];\n\n\t\t\td0![0] =   p3;\n\t\t\td1![3] = - p3;\n\t\t\td2![0] =   p2;\n\t\t\td3![3] =   p2;\n\n\t\t\tlet mut p1 =  e![4]*b![5] - e![5]*b![4];\n\t\t\tlet mut p0 = -e![4]*b![4] - e![5]*b![5];\n\n\t\t\td0![1] =   p1;\n\t\t\td1![2] = - p1;\n\t\t\td2![1] =   p0;\n\t\t\td3![2] =   p0;\n\n\t\t\tp3 =  e![2]*b![3] - e![3]*b![2];\n\t\t\tp2 = -e![2]*b![2] - e![3]*b![3];\n\n\t\t\td0![2] =   p3;\n\t\t\td1![1] = - p3;\n\t\t\td2![2] =   p2;\n\t\t\td3![1] =   p2;\n\n\t\t\tp1 =  e![0]*b![1] - e![1]*b![0];\n\t\t\tp0 = -e![0]*b![0] - e![1]*b![1];\n\n\t\t\td0![3] =   p1;\n\t\t\td1![0] = - p1;\n\t\t\td2![3] =   p0;\n\t\t\td3![0] =   p0;\n\n\t\t\tbreak_if_sub_overflows!(e_offs, 8);\n\t\t\tb_offs -= 8;\n\t\t\td0_offs += 4;\n\t\t\td2_offs += 4;\n\t\t\td1_offs -= 4;\n\t\t\td3_offs -= 4;\n\t\t}\n\t}\n}\n\n#[allow(dead_code)]\npub fn inverse_mdct_naive(cached_bd :&CachedBlocksizeDerived, buffer :&mut[f32]) {\n\tlet n = buffer.len();\n\tlet n2 = n >> 1;\n\tlet n4 = n >> 2;\n\tlet n8 = n >> 3;\n\tlet n3_4 = n - n4;\n\n\tlet mut u = [0.0; 1 << 13];\n\tlet mut xa = [0.0; 1 << 13];\n\tlet mut v = [0.0; 1 << 13];\n\tlet mut w = [0.0; 1 << 13];\n\n\t// retrieve the cached twiddle factors\n\tlet ctf = &cached_bd.twiddle_factors;\n\tlet a :&[f32] = &ctf.a;\n\tlet b :&[f32] = &ctf.b;\n\tlet c :&[f32] = &ctf.c;\n\n\t// IMDCT algorithm from \"The use of multirate filter banks for coding of high quality digital audio\"\n\t// Note there are bugs in that pseudocode, presumably due to them attempting\n\t// to rename the arrays nicely rather than representing the way their actual\n\t// implementation bounces buffers back and forth. As a result, even in the\n\t// \"some formulars corrected\" version, a direct implementation fails. These\n\t// are noted below as \"paper bug\".\n\n\t// copy and reflect spectral data\n\tfor k in 0 .. n2 {\n\t\tu[k] = buffer[k];\n\t}\n\tfor k in n2 .. n {\n\t\tu[k] = -buffer[n - k - 1];\n\t}\n\n\tlet mut k2 = 0;\n\tlet mut k4 = 0;\n\n\t// kernel from paper\n\t// step 1\n\twhile k2 < n2 { // n4 iterations\n\t\tv[n-k4-1] = (u[k4] - u[n-k4-1]) * a[k2]   - (u[k4+2] - u[n-k4-3])*a[k2+1];\n\t\tv[n-k4-3] = (u[k4] - u[n-k4-1]) * a[k2+1] + (u[k4+2] - u[n-k4-3])*a[k2];\n\t\tk2 += 2;\n\t\tk4 += 4;\n\t}\n\t// step 2\n\tk4 = 0;\n\twhile k4 < n2 { // n8 iterations\n\t\tw[n2+3+k4] = v[n2+3+k4] + v[k4+3];\n\t\tw[n2+1+k4] = v[n2+1+k4] + v[k4+1];\n\t\tw[k4+3]    = (v[n2+3+k4] - v[k4+3])*a[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*a[n2-3-k4];\n\t\tw[k4+1]    = (v[n2+1+k4] - v[k4+1])*a[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*a[n2-3-k4];\n\t\tk4 += 4;\n\t}\n\n\t// step 3\n\tlet ld :usize = (::ilog(n as u64) - 1) as usize;\n\tfor l in 0 .. ld - 3 {\n\t\tlet k0 = n >> (l+2);\n\t\tlet k1 = 1 << (l+3);\n\t\tlet rlim = n >> (l+4);\n\t\tlet slim = 1 << (l+1);\n\t\tlet mut r4 = 0;\n\t\tfor r in 0 .. rlim {\n\t\t\tlet mut s2 = 0;\n\t\t\tfor _ in 0 .. slim {\n\t\t\t\tu[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];\n\t\t\t\tu[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];\n\t\t\t\tu[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * a[r*k1]\n\t\t\t\t\t- (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * a[r*k1+1];\n\t\t\t\tu[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * a[r*k1]\n\t\t\t\t\t+ (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * a[r*k1+1];\n\t\t\t\ts2 += 2;\n\t\t\t}\n\t\t\tr4 += 4;\n\t\t}\n\t\tif l+1 < ld-3 {\n\t\t\t// paper bug: ping-ponging of u&w here is omitted\n\t\t\tw.copy_from_slice(&u);\n\t\t}\n\t}\n\n\t// step 4\n\tfor i in 0 .. n8 {\n\t\tlet j = (::bit_reverse(i as u32) >> (32-ld+3)) as usize;\n\t\tassert!(j < n8);\n\t\tif i == j {\n\t\t\t// paper bug: original code probably swapped in place; if copying,\n\t\t\t//            need to directly copy in this case\n\t\t\tlet ii = i << 3;\n\t\t\tv[ii+1] = u[ii+1];\n\t\t\tv[ii+3] = u[ii+3];\n\t\t\tv[ii+5] = u[ii+5];\n\t\t\tv[ii+7] = u[ii+7];\n\t\t} else if i < j {\n\t\t\tlet ii = i << 3;\n\t\t\tlet j8 = j << 3;\n\t\t\tv[j8+1] = u[ii+1];\n\t\t\tv[ii+1] = u[j8 + 1];\n\t\t\tv[j8+3] = u[ii+3];\n\t\t\tv[ii+3] = u[j8 + 3];\n\t\t\tv[j8+5] = u[ii+5];\n\t\t\tv[ii+5] = u[j8 + 5];\n\t\t\tv[j8+7] = u[ii+7];\n\t\t\tv[ii+7] = u[j8 + 7];\n\t\t}\n\t}\n\n\t// step 5\n\tfor k in 0 .. n2 {\n\t\tw[k] = v[k*2+1];\n\t}\n\t// step 6\n\tlet mut k2 = 0;\n\tlet mut k4 = 0;\n\twhile k2 < n4 { // n8 iterations\n\t\tu[n-1-k2] = w[k4];\n\t\tu[n-2-k2] = w[k4+1];\n\t\tu[n3_4 - 1 - k2] = w[k4+2];\n\t\tu[n3_4 - 2 - k2] = w[k4+3];\n\t\tk2 += 2;\n\t\tk4 += 4;\n\t}\n\t// step 7\n\tk2 = 0;\n\twhile k2 < n4 { // n8 iterations\n\t\tv[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;\n\t\tv[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;\n\t\tv[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;\n\t\tv[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;\n\t\tk2 += 2;\n\t}\n\t// step 8\n\tk2 = 0;\n\tfor k in 0 .. n4 {\n\t\txa[k]      = v[k2+n2]*b[k2  ] + v[k2+1+n2]*b[k2+1];\n\t\txa[n2-1-k] = v[k2+n2]*b[k2+1] - v[k2+1+n2]*b[k2  ];\n\t\tk2 += 2;\n\t}\n\n\t// decode kernel to output\n\n\tfor i in 0 .. n4 {\n\t\tbuffer[i] = xa[i + n4];\n\t}\n\tfor i in n4 .. n3_4 {\n\t\tbuffer[i] = -xa[n3_4 - i - 1];\n\t}\n\tfor i in n3_4 .. n {\n\t\tbuffer[i] = -xa[i - n3_4];\n\t}\n}\n\n#[cfg(test)]\n#[test]\nfn test_imdct_naive() {\n\tuse imdct_test::*;\n\tlet mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1);\n\tlet cbd = CachedBlocksizeDerived::from_blocksize(8);\n\tinverse_mdct_naive(&cbd, &mut arr_1);\n\tlet mismatches = fuzzy_compare_array(\n\t\t&arr_1, &IMDCT_OUTPUT_TEST_ARR_1,\n\t\t0.00005, true);\n\tlet mismatches_limit = 0;\n\tif mismatches > mismatches_limit {\n\t\tpanic!(\"Numer of mismatches {} was larger than limit of {}\",\n\t\t\tmismatches, mismatches_limit);\n\t}\n}\n\n#[cfg(test)]\n#[test]\nfn test_imdct() {\n\tuse imdct_test::*;\n\tlet mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1);\n\tlet blocksize = 8;\n\tlet cbd = CachedBlocksizeDerived::from_blocksize(blocksize);\n\tinverse_mdct(&cbd, &mut arr_1, blocksize);\n\tlet mismatches = fuzzy_compare_array(\n\t\t&arr_1, &IMDCT_OUTPUT_TEST_ARR_1,\n\t\t0.00005, true);\n\tlet mismatches_limit = 0;\n\tif mismatches > mismatches_limit {\n\t\tpanic!(\"Numer of mismatches {} was larger than limit of {}\",\n\t\t\tmismatches, mismatches_limit);\n\t}\n}\n"
  },
  {
    "path": "src/imdct_test.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n#![allow(dead_code)]\n\npub static IMDCT_INPUT_TEST_ARR_1 :[f32; 128] =\n[-0.01894, -0.10670,  0.51740,  0.39750,\n  0.03894,  0.00692,  0.00000,  0.00369,\n  0.00092, -0.00143, -0.00056,  0.00087,\n  0.00067, -0.00063, -0.00056,  0.00052,\n  0.00046, -0.00043, -0.00041,  0.00036,\n  0.00034, -0.00030, -0.00028,  0.00025,\n  0.00025, -0.00012, -0.00022,  0.00010,\n  0.00019, -0.00010, -0.00018,  0.00008,\n  0.00016, -0.00007, -0.00015,  0.00007,\n  0.00013, -0.00006, -0.00012,  0.00006,\n  0.00011, -0.00005, -0.00010,  0.00005,\n  0.00009, -0.00004, -0.00008,  0.00004,\n  0.00008,  0.00000, -0.00007,  0.00000,\n  0.00007,  0.00000, -0.00007,  0.00000,\n  0.00007,  0.00000, -0.00007,  0.00000,\n  0.00007,  0.00000, -0.00006,  0.00000,\n  0.00006,  0.00000, -0.00006,  0.00000,\n  0.00006,  0.00000, -0.00005,  0.00000,\n  0.00005,  0.00000, -0.00003,  0.00000,\n  0.00003,  0.00000, -0.00003,  0.00000,\n  0.00003,  0.00000, -0.00003,  0.00000,\n  0.00003,  0.00000, -0.00003,  0.00000,\n  0.00004,  0.00000, -0.00004,  0.00000,\n  0.00005,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000];\n\npub static IMDCT_OUTPUT_TEST_ARR_1 :[f32; 256] =\n[ 0.03325,  0.07520,  0.11729,  0.15753,\n  0.19588,  0.23308,  0.26823,  0.30140,\n  0.33234,  0.36078,  0.38742,  0.41169,\n  0.43321,  0.45243,  0.46889,  0.48269,\n  0.49426,  0.50325,  0.50983,  0.51412,\n  0.51613,  0.51621,  0.51417,  0.51004,\n  0.50417,  0.49634,  0.48682,  0.47595,\n  0.46349,  0.44974,  0.43492,  0.41903,\n  0.40238,  0.38495,  0.36682,  0.34831,\n  0.32932,  0.31015,  0.29104,  0.27183,\n  0.25285,  0.23427,  0.21602,  0.19839,\n  0.18134,  0.16489,  0.14925,  0.13434,\n  0.12030,  0.10721,  0.09486,  0.08348,\n  0.07306,  0.06339,  0.05463,  0.04662,\n  0.03925,  0.03264,  0.02655,  0.02098,\n  0.01586,  0.01098,  0.00648,  0.00219,\n -0.00219, -0.00648, -0.01098, -0.01586,\n -0.02098, -0.02655, -0.03264, -0.03925,\n -0.04662, -0.05463, -0.06339, -0.07306,\n -0.08348, -0.09486, -0.10721, -0.12030,\n -0.13434, -0.14925, -0.16489, -0.18134,\n -0.19839, -0.21602, -0.23427, -0.25285,\n -0.27183, -0.29104, -0.31015, -0.32932,\n -0.34831, -0.36682, -0.38495, -0.40238,\n -0.41903, -0.43492, -0.44974, -0.46349,\n -0.47595, -0.48682, -0.49634, -0.50417,\n -0.51004, -0.51417, -0.51621, -0.51613,\n -0.51412, -0.50983, -0.50325, -0.49426,\n -0.48269, -0.46889, -0.45243, -0.43321,\n -0.41169, -0.38742, -0.36078, -0.33234,\n -0.30140, -0.26823, -0.23308, -0.19588,\n -0.15753, -0.11729, -0.07520, -0.03325,\n  0.01147,  0.06175,  0.11352,  0.16419,\n  0.21479,  0.26472,  0.31382,  0.36215,\n  0.40885,  0.45420,  0.49798,  0.53953,\n  0.57931,  0.61680,  0.65136,  0.68325,\n  0.71206,  0.73749,  0.75955,  0.77780,\n  0.79226,  0.80284,  0.80927,  0.81177,\n  0.80999,  0.80374,  0.79336,  0.77856,\n  0.75936,  0.73598,  0.70826,  0.67643,\n  0.64070,  0.60110,  0.55796,  0.51130,\n  0.46132,  0.40853,  0.35296,  0.29496,\n  0.23502,  0.17323,  0.11014,  0.04621,\n -0.01834, -0.08299, -0.14746, -0.21136,\n -0.27409, -0.33545, -0.39494, -0.45208,\n -0.50668, -0.55817, -0.60612, -0.65041,\n -0.69058, -0.72643, -0.75773, -0.78409,\n -0.80548, -0.82165, -0.83246, -0.83802,\n -0.83802, -0.83246, -0.82165, -0.80548,\n -0.78409, -0.75773, -0.72643, -0.69058,\n -0.65041, -0.60612, -0.55817, -0.50668,\n -0.45208, -0.39494, -0.33545, -0.27409,\n -0.21136, -0.14746, -0.08299, -0.01834,\n  0.04621,  0.11014,  0.17323,  0.23502,\n  0.29496,  0.35296,  0.40853,  0.46132,\n  0.51130,  0.55796,  0.60110,  0.64070,\n  0.67643,  0.70826,  0.73598,  0.75936,\n  0.77856,  0.79336,  0.80374,  0.80999,\n  0.81177,  0.80927,  0.80284,  0.79226,\n  0.77780,  0.75955,  0.73749,  0.71206,\n  0.68325,  0.65136,  0.61680,  0.57931,\n  0.53953,  0.49798,  0.45420,  0.40885,\n  0.36215,  0.31382,  0.26472,  0.21479,\n  0.16419,  0.11352,  0.06175,  0.01147];\n\npub static IMDCT_INPUT_TEST_ARR_2 :[f32; 128] =\n[ 0.07109,  0.29427,  0.58470, -0.36304,\n  0.05009, -0.01145,  0.00184,  0.00063,\n -0.00020, -0.00018,  0.00015,  0.00013,\n -0.00011, -0.00009,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000];\n\npub static IMDCT_OUTPUT_TEST_ARR_2 :[f32; 256] =\n[-0.78862, -0.79274, -0.79359, -0.79110,\n -0.78522, -0.77592, -0.76317, -0.74696,\n -0.72731, -0.70422, -0.67775, -0.64795,\n -0.61489, -0.57868, -0.53943, -0.49729,\n -0.45242, -0.40500, -0.35524, -0.30338,\n -0.24966, -0.19435, -0.13774, -0.08012,\n -0.02181,  0.03686,  0.09556,  0.15395,\n  0.21166,  0.26837,  0.32370,  0.37732,\n  0.42887,  0.47801,  0.52442,  0.56776,\n  0.60774,  0.64406,  0.67645,  0.70467,\n  0.72849,  0.74771,  0.76217,  0.77173,\n  0.77628,  0.77576,  0.77013,  0.75940,\n  0.74361,  0.72283,  0.69717,  0.66679,\n  0.63188,  0.59264,  0.54935,  0.50227,\n  0.45173,  0.39806,  0.34162,  0.28282,\n  0.22204,  0.15972,  0.09628,  0.03217,\n -0.03217, -0.09628, -0.15972, -0.22204,\n -0.28282, -0.34162, -0.39806, -0.45173,\n -0.50227, -0.54935, -0.59264, -0.63188,\n -0.66679, -0.69717, -0.72283, -0.74361,\n -0.75940, -0.77013, -0.77576, -0.77628,\n -0.77173, -0.76217, -0.74771, -0.72849,\n -0.70467, -0.67645, -0.64406, -0.60774,\n -0.56776, -0.52442, -0.47801, -0.42887,\n -0.37732, -0.32370, -0.26837, -0.21166,\n -0.15395, -0.09556, -0.03686,  0.02181,\n  0.08012,  0.13774,  0.19435,  0.24966,\n  0.30338,  0.35524,  0.40500,  0.45242,\n  0.49729,  0.53943,  0.57868,  0.61489,\n  0.64795,  0.67775,  0.70422,  0.72731,\n  0.74696,  0.76317,  0.77592,  0.78522,\n  0.79110,  0.79359,  0.79274,  0.78862,\n  0.78129,  0.77084,  0.75738,  0.74100,\n  0.72184,  0.70003,  0.67572,  0.64906,\n  0.62022,  0.58938,  0.55672,  0.52243,\n  0.48671,  0.44973,  0.41171,  0.37283,\n  0.33328,  0.29325,  0.25290,  0.21241,\n  0.17195,  0.13166,  0.09170,  0.05219,\n  0.01327, -0.02493, -0.06232, -0.09878,\n -0.13422, -0.16855, -0.20169, -0.23358,\n -0.26416, -0.29339, -0.32122, -0.34763,\n -0.37261, -0.39615, -0.41827, -0.43897,\n -0.45828, -0.47624, -0.49288, -0.50825,\n -0.52239, -0.53536, -0.54722, -0.55801,\n -0.56779, -0.57662, -0.58455, -0.59163,\n -0.59793, -0.60348, -0.60833, -0.61255,\n -0.61616, -0.61922, -0.62176, -0.62383,\n -0.62543, -0.62662, -0.62740, -0.62778,\n -0.62778, -0.62740, -0.62662, -0.62543,\n -0.62383, -0.62176, -0.61922, -0.61616,\n -0.61255, -0.60833, -0.60348, -0.59793,\n -0.59163, -0.58455, -0.57662, -0.56779,\n -0.55801, -0.54722, -0.53536, -0.52239,\n -0.50825, -0.49288, -0.47624, -0.45828,\n -0.43897, -0.41827, -0.39615, -0.37261,\n -0.34763, -0.32122, -0.29339, -0.26416,\n -0.23358, -0.20169, -0.16855, -0.13422,\n -0.09878, -0.06232, -0.02493,  0.01327,\n  0.05219,  0.09170,  0.13166,  0.17195,\n  0.21241,  0.25290,  0.29325,  0.33328,\n  0.37283,  0.41171,  0.44973,  0.48671,\n  0.52243,  0.55672,  0.58938,  0.62022,\n  0.64906,  0.67572,  0.70003,  0.72184,\n  0.74100,  0.75738,  0.77084,  0.78129];\n\npub static IMDCT_INPUT_TEST_ARR_3 :[f32; 1024] =\n[-0.00325,  0.00916, -0.01147,  0.00942,\n -0.00442,  0.00059,  0.00000,  0.00430,\n -0.01291,  0.02373, -0.03052,  0.03141,\n -0.02273,  0.00975,  0.00000,  0.00836,\n -0.04179,  0.11284, -0.20060,  0.25075,\n -0.21732,  0.10448,  0.00000, -0.05433,\n  0.05886, -0.03806,  0.01525,  0.00000,\n -0.00474,  0.00209,  0.00184, -0.00488,\n  0.00573, -0.00379,  0.00111,  0.00209,\n -0.00277,  0.00325, -0.00215,  0.00126,\n  0.00000,  0.00000, -0.00043,  0.00153,\n -0.00202,  0.00208, -0.00157,  0.00079,\n -0.00026,  0.00000,  0.00000,  0.00023,\n -0.00046,  0.00065, -0.00043,  0.00020,\n  0.00020, -0.00038,  0.00057, -0.00036,\n  0.00018,  0.00000,  0.00000,  0.00000,\n  0.00016, -0.00032,  0.00030, -0.00030,\n  0.00014,  0.00014, -0.00013,  0.00013,\n  0.00000,  0.00000,  0.00012, -0.00012,\n  0.00000,  0.00011, -0.00022,  0.00020,\n -0.00010,  0.00000,  0.00010, -0.00009,\n  0.00000,  0.00000, -0.00008,  0.00008,\n -0.00008,  0.00000,  0.00007, -0.00014,\n  0.00007, -0.00007,  0.00000,  0.00007,\n  0.00000,  0.00000,  0.00006, -0.00012,\n  0.00006, -0.00006,  0.00000,  0.00005,\n -0.00005,  0.00005,  0.00000, -0.00005,\n  0.00005,  0.00000, -0.00005,  0.00005,\n -0.00009,  0.00004,  0.00000, -0.00004,\n  0.00004, -0.00004,  0.00000,  0.00004,\n -0.00004,  0.00004,  0.00000, -0.00004,\n  0.00007, -0.00003,  0.00003,  0.00000,\n -0.00003,  0.00003,  0.00000, -0.00003,\n  0.00003, -0.00003,  0.00003,  0.00000,\n -0.00003,  0.00003, -0.00003,  0.00000,\n  0.00003, -0.00003,  0.00000,  0.00000,\n -0.00002,  0.00005, -0.00002,  0.00000,\n  0.00002, -0.00002,  0.00002,  0.00000,\n -0.00002,  0.00002, -0.00002,  0.00000,\n  0.00002, -0.00004,  0.00004, -0.00002,\n  0.00000,  0.00002, -0.00002,  0.00000,\n  0.00002, -0.00002,  0.00002, -0.00002,\n  0.00000,  0.00001, -0.00003,  0.00001,\n  0.00000, -0.00001,  0.00001, -0.00001,\n  0.00000,  0.00001, -0.00002,  0.00001,\n  0.00000, -0.00001,  0.00001, -0.00001,\n  0.00000,  0.00001, -0.00001,  0.00001,\n  0.00000, -0.00001,  0.00002, -0.00002,\n  0.00001,  0.00000, -0.00001,  0.00001,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000, -0.00001,  0.00002,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000, -0.00001,  0.00002,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000,  0.00000,  0.00001,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00002, -0.00001,  0.00000,  0.00001,\n -0.00001,  0.00001,  0.00000, -0.00001,\n  0.00001, -0.00001,  0.00000,  0.00001,\n -0.00001,  0.00001,  0.00000, -0.00001,\n  0.00001, -0.00001,  0.00000,  0.00001,\n -0.00001,  0.00001,  0.00000, -0.00001,\n  0.00001, -0.00001,  0.00000,  0.00000,\n -0.00001,  0.00001,  0.00000, -0.00001,\n  0.00001, -0.00001,  0.00001,  0.00000,\n -0.00001,  0.00001, -0.00001,  0.00000,\n  0.00001, -0.00001,  0.00001,  0.00000,\n -0.00001,  0.00001, -0.00001,  0.00000,\n  0.00001, -0.00001,  0.00001,  0.00000,\n -0.00001,  0.00001, -0.00001,  0.00000,\n  0.00001, -0.00001,  0.00001,  0.00000,\n  0.00000,  0.00001, -0.00001,  0.00000,\n  0.00000, -0.00001,  0.00001, -0.00001,\n  0.00000,  0.00001, -0.00001,  0.00001,\n  0.00000, -0.00001,  0.00001, -0.00001,\n  0.00000,  0.00001, -0.00001,  0.00001,\n  0.00000,  0.00000,  0.00001, -0.00001,\n  0.00000,  0.00001, -0.00001,  0.00001,\n  0.00000, -0.00001,  0.00001, -0.00001,\n  0.00000,  0.00000, -0.00001,  0.00001,\n  0.00000,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000, -0.00001,  0.00001,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000, -0.00001,  0.00001,\n -0.00001,  0.00000,  0.00000, -0.00001,\n  0.00001,  0.00000, -0.00001,  0.00001,\n -0.00001,  0.00000,  0.00001, -0.00001,\n  0.00001,  0.00000,  0.00000,  0.00001,\n -0.00001,  0.00000,  0.00000, -0.00001,\n  0.00001, -0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000, -0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000, -0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n -0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000, -0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000,\n  0.00000,  0.00000,  0.00000,  0.00000];\n\npub static IMDCT_OUTPUT_TEST_ARR_3 :[f32; 2048] =\n[ 0.00454,  0.00669,  0.00892,  0.01121,\n  0.01351,  0.01581,  0.01811,  0.02041,\n  0.02267,  0.02487,  0.02702,  0.02908,\n  0.03102,  0.03282,  0.03452,  0.03617,\n  0.03774,  0.03921,  0.04058,  0.04183,\n  0.04296,  0.04392,  0.04472,  0.04535,\n  0.04582,  0.04612,  0.04624,  0.04619,\n  0.04598,  0.04560,  0.04503,  0.04427,\n  0.04332,  0.04220,  0.04090,  0.03945,\n  0.03782,  0.03599,  0.03400,  0.03185,\n  0.02955,  0.02709,  0.02447,  0.02172,\n  0.01883,  0.01580,  0.01262,  0.00933,\n  0.00593,  0.00242, -0.00120, -0.00491,\n -0.00870, -0.01258, -0.01650, -0.02046,\n -0.02445, -0.02847, -0.03246, -0.03641,\n -0.04032, -0.04420, -0.04798, -0.05160,\n -0.05506, -0.05837, -0.06151, -0.06445,\n -0.06721, -0.06980, -0.07217, -0.07432,\n -0.07628, -0.07803, -0.07947, -0.08055,\n -0.08134, -0.08185, -0.08203, -0.08187,\n -0.08141, -0.08063, -0.07948, -0.07797,\n -0.07616, -0.07403, -0.07150, -0.06857,\n -0.06532, -0.06174, -0.05777, -0.05342,\n -0.04875, -0.04380, -0.03852, -0.03292,\n -0.02705, -0.02093, -0.01456, -0.00799,\n -0.00126,  0.00564,  0.01270,  0.01986,\n  0.02705,  0.03427,  0.04154,  0.04878,\n  0.05595,  0.06301,  0.06997,  0.07678,\n  0.08341,  0.08986,  0.09613,  0.10215,\n  0.10790,  0.11335,  0.11850,  0.12329,\n  0.12768,  0.13165,  0.13521,  0.13831,\n  0.14092,  0.14300,  0.14456,  0.14557,\n  0.14601,  0.14585,  0.14512,  0.14380,\n  0.14184,  0.13919,  0.13590,  0.13201,\n  0.12753,  0.12241,  0.11665,  0.11028,\n  0.10334,  0.09586,  0.08786,  0.07935,\n  0.07030,  0.06069,  0.05056,  0.03998,\n  0.02900,  0.01763,  0.00587, -0.00621,\n -0.01856, -0.03113, -0.04387, -0.05675,\n -0.06972, -0.08274, -0.09573, -0.10864,\n -0.12143, -0.13403, -0.14638, -0.15842,\n -0.17010, -0.18136, -0.19213, -0.20237,\n -0.21201, -0.22098, -0.22922, -0.23671,\n -0.24342, -0.24927, -0.25419, -0.25819,\n -0.26122, -0.26319, -0.26408, -0.26389,\n -0.26263, -0.26023, -0.25666, -0.25195,\n -0.24610, -0.23908, -0.23088, -0.22152,\n -0.21101, -0.19934, -0.18655, -0.17271,\n -0.15782, -0.14189, -0.12498, -0.10722,\n -0.08867, -0.06931, -0.04915, -0.02828,\n -0.00678,  0.01522,  0.03764,  0.06037,\n  0.08332,  0.10640,  0.12956,  0.15278,\n  0.17592,  0.19880,  0.22131,  0.24344,\n  0.26512,  0.28620,  0.30652,  0.32606,\n  0.34475,  0.36246,  0.37904,  0.39443,\n  0.40859,  0.42139,  0.43269,  0.44243,\n  0.45058,  0.45704,  0.46171,  0.46456,\n  0.46555,  0.46464,  0.46175,  0.45689,\n  0.45002,  0.44112,  0.43016,  0.41715,\n  0.40211,  0.38504,  0.36597,  0.34494,\n  0.32197,  0.29714,  0.27052,  0.24215,\n  0.21211,  0.18049,  0.14736,  0.11283,\n  0.07703,  0.04012,  0.00221, -0.03663,\n -0.07619, -0.11623, -0.15668, -0.19747,\n -0.23835, -0.27906, -0.31956, -0.35988,\n -0.39967, -0.43840, -0.47617, -0.51362,\n -0.55083, -0.58678, -0.62029, -0.65106,\n -0.67937, -0.70523, -0.72830, -0.74839,\n -0.76555, -0.77976, -0.79086, -0.79878,\n -0.80358, -0.80526, -0.80376, -0.79907,\n -0.79124, -0.78031, -0.76627, -0.74919,\n -0.72918, -0.70631, -0.68065, -0.65230,\n -0.62140, -0.58808, -0.55245, -0.51464,\n -0.47484, -0.43321, -0.38990, -0.34508,\n -0.29891, -0.25161, -0.20336, -0.15431,\n -0.10469, -0.05472, -0.00459,  0.04555,\n  0.09552,  0.14508,  0.19401,  0.24218,\n  0.28943,  0.33551,  0.38019,  0.42336,\n  0.46488,  0.50457,  0.54222,  0.57769,\n  0.61091,  0.64174,  0.67006,  0.69575,\n  0.71872,  0.73889,  0.75619,  0.77058,\n  0.78200,  0.79037,  0.79562,  0.79770,\n  0.79662,  0.79238,  0.78505,  0.77463,\n  0.76119,  0.74477,  0.72543,  0.70323,\n  0.67824,  0.65061,  0.62046,  0.58787,\n  0.55293,  0.51582,  0.47673,  0.43580,\n  0.39314,  0.34891,  0.30334,  0.25659,\n  0.20882,  0.16024,  0.11106,  0.06146,\n  0.01160, -0.03830, -0.08801, -0.13736,\n -0.18618, -0.23428, -0.28147, -0.32756,\n -0.37239, -0.41576, -0.45752, -0.49750,\n -0.53555, -0.57148, -0.60517, -0.63654,\n -0.66545, -0.69174, -0.71533, -0.73615,\n -0.75411, -0.76911, -0.78108, -0.79000,\n -0.79583, -0.79849, -0.79799, -0.79436,\n -0.78766, -0.77792, -0.76515, -0.74939,\n -0.73069, -0.70911, -0.68473, -0.65765,\n -0.62797, -0.59582, -0.56134, -0.52467,\n -0.48594, -0.44529, -0.40288, -0.35886,\n -0.31341, -0.26671, -0.21892, -0.17027,\n -0.12095, -0.07118, -0.02110,  0.02908,\n  0.07913,  0.12885,  0.17807,  0.22659,\n  0.27422,  0.32078,  0.36610,  0.41003,\n  0.45236,  0.49295,  0.53165,  0.56828,\n  0.60270,  0.63479,  0.66442,  0.69145,\n  0.71576,  0.73727,  0.75592,  0.77161,\n  0.78424,  0.79381,  0.80029,  0.80362,\n  0.80376,  0.80075,  0.79461,  0.78533,\n  0.77293,  0.75749,  0.73909,  0.71773,\n  0.69351,  0.66657,  0.63701,  0.60492,\n  0.57044,  0.53374,  0.49490,  0.45404,\n  0.41137,  0.36712,  0.32143,  0.27442,\n  0.22640,  0.17775,  0.12871,  0.07942,\n  0.03003, -0.01923, -0.06821, -0.11679,\n -0.16482, -0.21214, -0.25863, -0.30421,\n -0.34876, -0.39211, -0.43416, -0.47488,\n -0.51414, -0.55183, -0.58788, -0.62226,\n -0.65487, -0.68559, -0.71439, -0.74126,\n -0.76612, -0.78888, -0.80949, -0.82795,\n -0.84420, -0.85817, -0.86982, -0.87913,\n -0.88607, -0.89062, -0.89276, -0.89248,\n -0.88975, -0.88456, -0.87692, -0.86685,\n -0.85432, -0.83934, -0.82193, -0.80214,\n -0.78002, -0.75561, -0.72896, -0.70016,\n -0.66925, -0.63629, -0.60139, -0.56467,\n -0.52620, -0.48608, -0.44443, -0.40142,\n -0.35720, -0.31183, -0.26544, -0.21822,\n -0.17036, -0.12204, -0.07337, -0.02448,\n  0.02448,  0.07337,  0.12204,  0.17036,\n  0.21822,  0.26544,  0.31183,  0.35720,\n  0.40142,  0.44443,  0.48608,  0.52620,\n  0.56467,  0.60139,  0.63629,  0.66925,\n  0.70016,  0.72896,  0.75561,  0.78002,\n  0.80214,  0.82193,  0.83934,  0.85432,\n  0.86685,  0.87692,  0.88456,  0.88975,\n  0.89248,  0.89276,  0.89062,  0.88607,\n  0.87913,  0.86982,  0.85817,  0.84420,\n  0.82795,  0.80949,  0.78888,  0.76612,\n  0.74126,  0.71439,  0.68559,  0.65487,\n  0.62226,  0.58788,  0.55183,  0.51414,\n  0.47488,  0.43416,  0.39211,  0.34876,\n  0.30421,  0.25863,  0.21214,  0.16482,\n  0.11679,  0.06821,  0.01923, -0.03003,\n -0.07942, -0.12871, -0.17775, -0.22640,\n -0.27442, -0.32143, -0.36712, -0.41137,\n -0.45404, -0.49490, -0.53374, -0.57044,\n -0.60492, -0.63701, -0.66657, -0.69351,\n -0.71773, -0.73909, -0.75749, -0.77293,\n -0.78533, -0.79461, -0.80075, -0.80376,\n -0.80362, -0.80029, -0.79381, -0.78424,\n -0.77161, -0.75592, -0.73727, -0.71576,\n -0.69145, -0.66442, -0.63479, -0.60270,\n -0.56828, -0.53165, -0.49295, -0.45236,\n -0.41003, -0.36610, -0.32078, -0.27422,\n -0.22659, -0.17807, -0.12885, -0.07913,\n -0.02908,  0.02110,  0.07118,  0.12095,\n  0.17027,  0.21892,  0.26671,  0.31341,\n  0.35886,  0.40288,  0.44529,  0.48594,\n  0.52467,  0.56134,  0.59582,  0.62797,\n  0.65765,  0.68473,  0.70911,  0.73069,\n  0.74939,  0.76515,  0.77792,  0.78766,\n  0.79436,  0.79799,  0.79849,  0.79583,\n  0.79000,  0.78108,  0.76911,  0.75411,\n  0.73615,  0.71533,  0.69174,  0.66545,\n  0.63654,  0.60517,  0.57148,  0.53555,\n  0.49750,  0.45752,  0.41576,  0.37239,\n  0.32756,  0.28147,  0.23428,  0.18618,\n  0.13736,  0.08801,  0.03830, -0.01160,\n -0.06146, -0.11106, -0.16024, -0.20882,\n -0.25659, -0.30334, -0.34891, -0.39314,\n -0.43580, -0.47673, -0.51582, -0.55293,\n -0.58787, -0.62046, -0.65061, -0.67824,\n -0.70323, -0.72543, -0.74477, -0.76119,\n -0.77463, -0.78505, -0.79238, -0.79662,\n -0.79770, -0.79562, -0.79037, -0.78200,\n -0.77058, -0.75619, -0.73889, -0.71872,\n -0.69575, -0.67006, -0.64174, -0.61091,\n -0.57769, -0.54222, -0.50457, -0.46488,\n -0.42336, -0.38019, -0.33551, -0.28943,\n -0.24218, -0.19401, -0.14508, -0.09552,\n -0.04555,  0.00459,  0.05472,  0.10469,\n  0.15431,  0.20336,  0.25161,  0.29891,\n  0.34508,  0.38990,  0.43321,  0.47484,\n  0.51464,  0.55245,  0.58808,  0.62140,\n  0.65230,  0.68065,  0.70631,  0.72918,\n  0.74919,  0.76627,  0.78031,  0.79124,\n  0.79907,  0.80376,  0.80526,  0.80358,\n  0.79878,  0.79086,  0.77976,  0.76555,\n  0.74839,  0.72830,  0.70523,  0.67937,\n  0.65106,  0.62029,  0.58678,  0.55083,\n  0.51362,  0.47617,  0.43840,  0.39967,\n  0.35988,  0.31956,  0.27906,  0.23835,\n  0.19747,  0.15668,  0.11623,  0.07619,\n  0.03663, -0.00221, -0.04012, -0.07703,\n -0.11283, -0.14736, -0.18049, -0.21211,\n -0.24215, -0.27052, -0.29714, -0.32197,\n -0.34494, -0.36597, -0.38504, -0.40211,\n -0.41715, -0.43016, -0.44112, -0.45002,\n -0.45689, -0.46175, -0.46464, -0.46555,\n -0.46456, -0.46171, -0.45704, -0.45058,\n -0.44243, -0.43269, -0.42139, -0.40859,\n -0.39443, -0.37904, -0.36246, -0.34475,\n -0.32606, -0.30652, -0.28620, -0.26512,\n -0.24344, -0.22131, -0.19880, -0.17592,\n -0.15278, -0.12956, -0.10640, -0.08332,\n -0.06037, -0.03764, -0.01522,  0.00678,\n  0.02828,  0.04915,  0.06931,  0.08867,\n  0.10722,  0.12498,  0.14189,  0.15782,\n  0.17271,  0.18655,  0.19934,  0.21101,\n  0.22152,  0.23088,  0.23908,  0.24610,\n  0.25195,  0.25666,  0.26023,  0.26263,\n  0.26389,  0.26408,  0.26319,  0.26122,\n  0.25819,  0.25419,  0.24927,  0.24342,\n  0.23671,  0.22922,  0.22098,  0.21201,\n  0.20237,  0.19213,  0.18136,  0.17010,\n  0.15842,  0.14638,  0.13403,  0.12143,\n  0.10864,  0.09573,  0.08274,  0.06972,\n  0.05675,  0.04387,  0.03113,  0.01856,\n  0.00621, -0.00587, -0.01763, -0.02900,\n -0.03998, -0.05056, -0.06069, -0.07030,\n -0.07935, -0.08786, -0.09586, -0.10334,\n -0.11028, -0.11665, -0.12241, -0.12753,\n -0.13201, -0.13590, -0.13919, -0.14184,\n -0.14380, -0.14512, -0.14585, -0.14601,\n -0.14557, -0.14456, -0.14300, -0.14092,\n -0.13831, -0.13521, -0.13165, -0.12768,\n -0.12329, -0.11850, -0.11335, -0.10790,\n -0.10215, -0.09613, -0.08986, -0.08341,\n -0.07678, -0.06997, -0.06301, -0.05595,\n -0.04878, -0.04154, -0.03427, -0.02705,\n -0.01986, -0.01270, -0.00564,  0.00126,\n  0.00799,  0.01456,  0.02093,  0.02705,\n  0.03292,  0.03852,  0.04380,  0.04875,\n  0.05342,  0.05777,  0.06174,  0.06532,\n  0.06857,  0.07150,  0.07403,  0.07616,\n  0.07797,  0.07948,  0.08063,  0.08141,\n  0.08187,  0.08203,  0.08185,  0.08134,\n  0.08055,  0.07947,  0.07803,  0.07628,\n  0.07432,  0.07217,  0.06980,  0.06721,\n  0.06445,  0.06151,  0.05837,  0.05506,\n  0.05160,  0.04798,  0.04420,  0.04032,\n  0.03641,  0.03246,  0.02847,  0.02445,\n  0.02046,  0.01650,  0.01258,  0.00870,\n  0.00491,  0.00120, -0.00242, -0.00593,\n -0.00933, -0.01262, -0.01580, -0.01883,\n -0.02172, -0.02447, -0.02709, -0.02955,\n -0.03185, -0.03400, -0.03599, -0.03782,\n -0.03945, -0.04090, -0.04220, -0.04332,\n -0.04427, -0.04503, -0.04560, -0.04598,\n -0.04619, -0.04624, -0.04612, -0.04582,\n -0.04535, -0.04472, -0.04392, -0.04296,\n -0.04183, -0.04058, -0.03921, -0.03774,\n -0.03617, -0.03452, -0.03282, -0.03102,\n -0.02908, -0.02702, -0.02487, -0.02267,\n -0.02041, -0.01811, -0.01581, -0.01351,\n -0.01121, -0.00892, -0.00669, -0.00454,\n -0.00245, -0.00037,  0.00166,  0.00363,\n  0.00553,  0.00739,  0.00920,  0.01093,\n  0.01258,  0.01417,  0.01567,  0.01707,\n  0.01838,  0.01960,  0.02070,  0.02166,\n  0.02251,  0.02328,  0.02395,  0.02446,\n  0.02486,  0.02516,  0.02535,  0.02539,\n  0.02529,  0.02509,  0.02481,  0.02442,\n  0.02395,  0.02339,  0.02273,  0.02195,\n  0.02110,  0.02017,  0.01915,  0.01802,\n  0.01687,  0.01573,  0.01459,  0.01339,\n  0.01217,  0.01094,  0.00967,  0.00836,\n  0.00707,  0.00583,  0.00458,  0.00331,\n  0.00204,  0.00083, -0.00035, -0.00154,\n -0.00268, -0.00376, -0.00481, -0.00585,\n -0.00686, -0.00779, -0.00867, -0.00948,\n -0.01019, -0.01082, -0.01139, -0.01190,\n -0.01230, -0.01262, -0.01291, -0.01316,\n -0.01332, -0.01340, -0.01342, -0.01341,\n -0.01334, -0.01322, -0.01307, -0.01287,\n -0.01262, -0.01235, -0.01207, -0.01177,\n -0.01144, -0.01111, -0.01076, -0.01039,\n -0.00998, -0.00955, -0.00911, -0.00862,\n -0.00810, -0.00756, -0.00701, -0.00641,\n -0.00578, -0.00515, -0.00455, -0.00395,\n -0.00339, -0.00285, -0.00231, -0.00174,\n -0.00117, -0.00063, -0.00009,  0.00050,\n  0.00113,  0.00172,  0.00224,  0.00270,\n  0.00313,  0.00352,  0.00390,  0.00423,\n  0.00447,  0.00462,  0.00471,  0.00478,\n  0.00488,  0.00500,  0.00510,  0.00517,\n  0.00522,  0.00528,  0.00533,  0.00532,\n  0.00525,  0.00518,  0.00509,  0.00495,\n  0.00478,  0.00459,  0.00441,  0.00422,\n  0.00402,  0.00382,  0.00361,  0.00338,\n  0.00315,  0.00293,  0.00270,  0.00243,\n  0.00214,  0.00183,  0.00150,  0.00113,\n  0.00073,  0.00033, -0.00008, -0.00048,\n -0.00087, -0.00126, -0.00164, -0.00199,\n -0.00232, -0.00263, -0.00293, -0.00320,\n -0.00342, -0.00361, -0.00379, -0.00396,\n -0.00409, -0.00421, -0.00433, -0.00443,\n -0.00451, -0.00457, -0.00461, -0.00462,\n -0.00464, -0.00468, -0.00469, -0.00466,\n -0.00460, -0.00451, -0.00439, -0.00419,\n -0.00397, -0.00376, -0.00355, -0.00332,\n -0.00309, -0.00287, -0.00263, -0.00236,\n -0.00208, -0.00183, -0.00156, -0.00128,\n -0.00099, -0.00067, -0.00032,  0.00007,\n  0.00048,  0.00090,  0.00136,  0.00182,\n  0.00225,  0.00266,  0.00305,  0.00343,\n  0.00376,  0.00405,  0.00432,  0.00459,\n  0.00483,  0.00504,  0.00521,  0.00536,\n  0.00547,  0.00554,  0.00559,  0.00564,\n  0.00571,  0.00576,  0.00577,  0.00576,\n  0.00577,  0.00577,  0.00574,  0.00571,\n  0.00570,  0.00566,  0.00554,  0.00543,\n  0.00532,  0.00511,  0.00476,  0.00445,\n  0.00426,  0.00402,  0.00359,  0.00312,\n  0.00283,  0.00259,  0.00217,  0.00165,\n  0.00131,  0.00112,  0.00084,  0.00042,\n  0.00002, -0.00027, -0.00057, -0.00096,\n -0.00137, -0.00174, -0.00213, -0.00258,\n -0.00304, -0.00349, -0.00392, -0.00435,\n -0.00476, -0.00515, -0.00550, -0.00581,\n -0.00610, -0.00637, -0.00659, -0.00675,\n -0.00688, -0.00700, -0.00708, -0.00711,\n -0.00712, -0.00714, -0.00713, -0.00707,\n -0.00701, -0.00696, -0.00689, -0.00680,\n -0.00669, -0.00658, -0.00644, -0.00627,\n -0.00607, -0.00582, -0.00550, -0.00515,\n -0.00476, -0.00431, -0.00379, -0.00327,\n -0.00275, -0.00219, -0.00157, -0.00098,\n -0.00045,  0.00010,  0.00072,  0.00135,\n  0.00188,  0.00233,  0.00275,  0.00318,\n  0.00365,  0.00416,  0.00463,  0.00497,\n  0.00524,  0.00556,  0.00592,  0.00624,\n  0.00650,  0.00676,  0.00703,  0.00722,\n  0.00733,  0.00740,  0.00747,  0.00751,\n  0.00750,  0.00745,  0.00738,  0.00728,\n  0.00716,  0.00704,  0.00689,  0.00673,\n  0.00656,  0.00637,  0.00614,  0.00588,\n  0.00560,  0.00528,  0.00489,  0.00447,\n  0.00403,  0.00358,  0.00307,  0.00254,\n  0.00201,  0.00150,  0.00097,  0.00042,\n -0.00012, -0.00063, -0.00111, -0.00156,\n -0.00199, -0.00239, -0.00277, -0.00311,\n -0.00347, -0.00382, -0.00412, -0.00435,\n -0.00457, -0.00481, -0.00506, -0.00529,\n -0.00552, -0.00576, -0.00598, -0.00617,\n -0.00639, -0.00663, -0.00683, -0.00695,\n -0.00700, -0.00701, -0.00698, -0.00691,\n -0.00682, -0.00673, -0.00660, -0.00641,\n -0.00622, -0.00605, -0.00587, -0.00565,\n -0.00538, -0.00512, -0.00487, -0.00459,\n -0.00430, -0.00399, -0.00368, -0.00336,\n -0.00304, -0.00272, -0.00242, -0.00212,\n -0.00181, -0.00151, -0.00123, -0.00098,\n -0.00072, -0.00047, -0.00024, -0.00003,\n  0.00018,  0.00039,  0.00059,  0.00080,\n  0.00101,  0.00123,  0.00144,  0.00167,\n  0.00194,  0.00223,  0.00252,  0.00283,\n  0.00317,  0.00351,  0.00382,  0.00412,\n  0.00443,  0.00471,  0.00494,  0.00519,\n  0.00549,  0.00582,  0.00611,  0.00635,\n  0.00655,  0.00673,  0.00690,  0.00706,\n  0.00715,  0.00714,  0.00707,  0.00699,\n  0.00688,  0.00673,  0.00654,  0.00634,\n  0.00612,  0.00586,  0.00558,  0.00532,\n  0.00506,  0.00476,  0.00443,  0.00409,\n  0.00374,  0.00336,  0.00295,  0.00252,\n  0.00205,  0.00154,  0.00102,  0.00050,\n -0.00003, -0.00056, -0.00106, -0.00151,\n -0.00193, -0.00235, -0.00274, -0.00309,\n -0.00340, -0.00369, -0.00395, -0.00418,\n -0.00440, -0.00459, -0.00473, -0.00483,\n -0.00490, -0.00494, -0.00495, -0.00493,\n -0.00490, -0.00484, -0.00475, -0.00466,\n -0.00456, -0.00443, -0.00427, -0.00413,\n -0.00401, -0.00386, -0.00364, -0.00338,\n -0.00313, -0.00291, -0.00268, -0.00241,\n -0.00211, -0.00183, -0.00157, -0.00131,\n -0.00100, -0.00065, -0.00033, -0.00008,\n  0.00012,  0.00029,  0.00041,  0.00047,\n  0.00051,  0.00053,  0.00053,  0.00050,\n  0.00046,  0.00038,  0.00025,  0.00010,\n -0.00005, -0.00020, -0.00035, -0.00050,\n -0.00061, -0.00070, -0.00080, -0.00089,\n -0.00095, -0.00099, -0.00104, -0.00109,\n -0.00109, -0.00104, -0.00099, -0.00095,\n -0.00089, -0.00080, -0.00070, -0.00061,\n -0.00050, -0.00035, -0.00020, -0.00005,\n  0.00010,  0.00025,  0.00038,  0.00046,\n  0.00050,  0.00053,  0.00053,  0.00051,\n  0.00047,  0.00041,  0.00029,  0.00012,\n -0.00008, -0.00033, -0.00065, -0.00100,\n -0.00131, -0.00157, -0.00183, -0.00211,\n -0.00241, -0.00268, -0.00291, -0.00313,\n -0.00338, -0.00364, -0.00386, -0.00401,\n -0.00413, -0.00427, -0.00443, -0.00456,\n -0.00466, -0.00475, -0.00484, -0.00490,\n -0.00493, -0.00495, -0.00494, -0.00490,\n -0.00483, -0.00473, -0.00459, -0.00440,\n -0.00418, -0.00395, -0.00369, -0.00340,\n -0.00309, -0.00274, -0.00235, -0.00193,\n -0.00151, -0.00106, -0.00056, -0.00003,\n  0.00050,  0.00102,  0.00154,  0.00205,\n  0.00252,  0.00295,  0.00336,  0.00374,\n  0.00409,  0.00443,  0.00476,  0.00506,\n  0.00532,  0.00558,  0.00586,  0.00612,\n  0.00634,  0.00654,  0.00673,  0.00688,\n  0.00699,  0.00707,  0.00714,  0.00715,\n  0.00706,  0.00690,  0.00673,  0.00655,\n  0.00635,  0.00611,  0.00582,  0.00549,\n  0.00519,  0.00494,  0.00471,  0.00443,\n  0.00412,  0.00382,  0.00351,  0.00317,\n  0.00283,  0.00252,  0.00223,  0.00194,\n  0.00167,  0.00144,  0.00123,  0.00101,\n  0.00080,  0.00059,  0.00039,  0.00018,\n -0.00003, -0.00024, -0.00047, -0.00072,\n -0.00098, -0.00123, -0.00151, -0.00181,\n -0.00212, -0.00242, -0.00272, -0.00304,\n -0.00336, -0.00368, -0.00399, -0.00430,\n -0.00459, -0.00487, -0.00512, -0.00538,\n -0.00565, -0.00587, -0.00605, -0.00622,\n -0.00641, -0.00660, -0.00673, -0.00682,\n -0.00691, -0.00698, -0.00701, -0.00700,\n -0.00695, -0.00683, -0.00663, -0.00639,\n -0.00617, -0.00598, -0.00576, -0.00552,\n -0.00529, -0.00506, -0.00481, -0.00457,\n -0.00435, -0.00412, -0.00382, -0.00347,\n -0.00311, -0.00277, -0.00239, -0.00199,\n -0.00156, -0.00111, -0.00063, -0.00012,\n  0.00042,  0.00097,  0.00150,  0.00201,\n  0.00254,  0.00307,  0.00358,  0.00403,\n  0.00447,  0.00489,  0.00528,  0.00560,\n  0.00588,  0.00614,  0.00637,  0.00656,\n  0.00673,  0.00689,  0.00704,  0.00716,\n  0.00728,  0.00738,  0.00745,  0.00750,\n  0.00751,  0.00747,  0.00740,  0.00733,\n  0.00722,  0.00703,  0.00676,  0.00650,\n  0.00624,  0.00592,  0.00556,  0.00524,\n  0.00497,  0.00463,  0.00416,  0.00365,\n  0.00318,  0.00275,  0.00233,  0.00188,\n  0.00135,  0.00072,  0.00010, -0.00045,\n -0.00098, -0.00157, -0.00219, -0.00275,\n -0.00327, -0.00379, -0.00431, -0.00476,\n -0.00515, -0.00550, -0.00582, -0.00607,\n -0.00627, -0.00644, -0.00658, -0.00669,\n -0.00680, -0.00689, -0.00696, -0.00701,\n -0.00707, -0.00713, -0.00714, -0.00712,\n -0.00711, -0.00708, -0.00700, -0.00688,\n -0.00675, -0.00659, -0.00637, -0.00610,\n -0.00581, -0.00550, -0.00515, -0.00476,\n -0.00435, -0.00392, -0.00349, -0.00304,\n -0.00258, -0.00213, -0.00174, -0.00137,\n -0.00096, -0.00057, -0.00027,  0.00002,\n  0.00042,  0.00084,  0.00112,  0.00131,\n  0.00165,  0.00217,  0.00259,  0.00283,\n  0.00312,  0.00359,  0.00402,  0.00426,\n  0.00445,  0.00476,  0.00511,  0.00532,\n  0.00543,  0.00554,  0.00566,  0.00570,\n  0.00571,  0.00574,  0.00577,  0.00577,\n  0.00576,  0.00577,  0.00576,  0.00571,\n  0.00564,  0.00559,  0.00554,  0.00547,\n  0.00536,  0.00521,  0.00504,  0.00483,\n  0.00459,  0.00432,  0.00405,  0.00376,\n  0.00343,  0.00305,  0.00266,  0.00225,\n  0.00182,  0.00136,  0.00090,  0.00048,\n  0.00007, -0.00032, -0.00067, -0.00099,\n -0.00128, -0.00156, -0.00183, -0.00208,\n -0.00236, -0.00263, -0.00287, -0.00309,\n -0.00332, -0.00355, -0.00376, -0.00397,\n -0.00419, -0.00439, -0.00451, -0.00460,\n -0.00466, -0.00469, -0.00468, -0.00464,\n -0.00462, -0.00461, -0.00457, -0.00451,\n -0.00443, -0.00433, -0.00421, -0.00409,\n -0.00396, -0.00379, -0.00361, -0.00342,\n -0.00320, -0.00293, -0.00263, -0.00232,\n -0.00199, -0.00164, -0.00126, -0.00087,\n -0.00048, -0.00008,  0.00033,  0.00073,\n  0.00113,  0.00150,  0.00183,  0.00214,\n  0.00243,  0.00270,  0.00293,  0.00315,\n  0.00338,  0.00361,  0.00382,  0.00402,\n  0.00422,  0.00441,  0.00459,  0.00478,\n  0.00495,  0.00509,  0.00518,  0.00525,\n  0.00532,  0.00533,  0.00528,  0.00522,\n  0.00517,  0.00510,  0.00500,  0.00488,\n  0.00478,  0.00471,  0.00462,  0.00447,\n  0.00423,  0.00390,  0.00352,  0.00313,\n  0.00270,  0.00224,  0.00172,  0.00113,\n  0.00050, -0.00009, -0.00063, -0.00117,\n -0.00174, -0.00231, -0.00285, -0.00339,\n -0.00395, -0.00455, -0.00515, -0.00578,\n -0.00641, -0.00701, -0.00756, -0.00810,\n -0.00862, -0.00911, -0.00955, -0.00998,\n -0.01039, -0.01076, -0.01111, -0.01144,\n -0.01177, -0.01207, -0.01235, -0.01262,\n -0.01287, -0.01307, -0.01322, -0.01334,\n -0.01341, -0.01342, -0.01340, -0.01332,\n -0.01316, -0.01291, -0.01262, -0.01230,\n -0.01190, -0.01139, -0.01082, -0.01019,\n -0.00948, -0.00867, -0.00779, -0.00686,\n -0.00585, -0.00481, -0.00376, -0.00268,\n -0.00154, -0.00035,  0.00083,  0.00204,\n  0.00331,  0.00458,  0.00583,  0.00707,\n  0.00836,  0.00967,  0.01094,  0.01217,\n  0.01339,  0.01459,  0.01573,  0.01687,\n  0.01802,  0.01915,  0.02017,  0.02110,\n  0.02195,  0.02273,  0.02339,  0.02395,\n  0.02442,  0.02481,  0.02509,  0.02529,\n  0.02539,  0.02535,  0.02516,  0.02486,\n  0.02446,  0.02395,  0.02328,  0.02251,\n  0.02166,  0.02070,  0.01960,  0.01838,\n  0.01707,  0.01567,  0.01417,  0.01258,\n  0.01093,  0.00920,  0.00739,  0.00553,\n  0.00363,  0.00166, -0.00037, -0.00245];\n\npub fn imdct_prepare(arr :&[f32]) -> Vec<f32> {\n\tlet mut res = Vec::with_capacity(arr.len() * 2);\n\tres.extend_from_slice(arr);\n\tfor _ in 0 .. arr.len() {\n\t\tres.push(0.);\n\t}\n\treturn res;\n}\n\npub fn fuzzy_compare_array(arr_a :&[f32], arr_b :&[f32],\n\t\tepsilon :f32, print_mismatches :bool) -> usize {\n\tlet mut mismatch_cnt :usize = 0;\n\tfor ((idx, entry_a), entry_b) in arr_a.iter().enumerate().zip(arr_b) {\n\t\tif (entry_a - entry_b).abs() >= epsilon {\n\t\t\tif print_mismatches {\n\t\t\t\tprintln!(\"Mismatch at idx {}. Expected {} but was {}\",\n\t\t\t\t\tidx, entry_a, entry_b);\n\t\t\t}\n\t\t\tmismatch_cnt += 1;\n\t\t}\n\t}\n\treturn mismatch_cnt;\n}\n"
  },
  {
    "path": "src/inside_ogg.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nHigher-level utilities for Ogg streams and files\n\nThis module provides higher level access to the library functionality,\nand useful helper methods for the Ogg `PacketReader` struct.\n*/\n\nuse ogg::{PacketReader, Packet};\nuse std::io::{Read, Seek};\nuse header::*;\nuse VorbisError;\nuse audio::{PreviousWindowRight, read_audio_packet,\n\tget_decoded_sample_count, read_audio_packet_generic};\nuse header::HeaderSet;\nuse samples::{Samples, InterleavedSamples};\n\n/// Reads the three vorbis headers from an ogg stream as well as stream serial information\n///\n/// Please note that this function doesn't work well with async\n/// I/O. In order to support this use case, enable the `async_ogg` feature,\n/// and use the `HeadersReader` struct instead.\npub fn read_headers<'a, T: Read + Seek + 'a>(rdr: &mut PacketReader<T>) ->\n\t\tResult<(HeaderSet, u32), VorbisError> {\n\tlet pck :Packet = try!(rdr.read_packet_expected());\n\tlet ident_hdr = try!(read_header_ident(&pck.data));\n\tlet stream_serial = pck.stream_serial();\n\n\tlet mut pck :Packet = try!(rdr.read_packet_expected());\n\twhile pck.stream_serial() != stream_serial {\n\t\tpck = try!(rdr.read_packet_expected());\n\t}\n\tlet comment_hdr = try!(read_header_comment(&pck.data));\n\n\tlet mut pck :Packet = try!(rdr.read_packet_expected());\n\twhile pck.stream_serial() != stream_serial {\n\t\tpck = try!(rdr.read_packet_expected());\n\t}\n\tlet setup_hdr = try!(read_header_setup(&pck.data, ident_hdr.audio_channels,\n\t\t(ident_hdr.blocksize_0, ident_hdr.blocksize_1)));\n\n\trdr.delete_unread_packets();\n\treturn Ok(((ident_hdr, comment_hdr, setup_hdr), pck.stream_serial()));\n}\n\n/**\nReading ogg/vorbis files or streams\n\nThis is a small helper struct to help reading ogg/vorbis files\nor streams in that format.\n\nIt only supports the main use case of pure audio ogg files streams.\nReading a file where vorbis is only one of multiple streams, like\nin the case of ogv, is not supported.\n\nIf you need support for this, you need to use the lower level methods\ninstead.\n*/\npub struct OggStreamReader<T: Read + Seek> {\n\trdr :PacketReader<T>,\n\tpwr :PreviousWindowRight,\n\n\tstream_serial :u32,\n\n\tpub ident_hdr :IdentHeader,\n\tpub comment_hdr :CommentHeader,\n\tpub setup_hdr :SetupHeader,\n\n\tcur_absgp :Option<u64>,\n}\n\nimpl<T: Read + Seek> OggStreamReader<T> {\n\t/// Constructs a new OggStreamReader from a given implementation of `Read + Seek`.\n\t///\n\t/// Please note that this function doesn't work well with async\n\t/// I/O. In order to support this use case, enable the `async_ogg` feature,\n\t/// and use the `HeadersReader` struct instead.\n\tpub fn new(rdr :T) ->\n\t\t\tResult<Self, VorbisError> {\n\t\tOggStreamReader::from_ogg_reader(PacketReader::new(rdr))\n\t}\n\t/// Constructs a new OggStreamReader from a given Ogg PacketReader.\n\t///\n\t/// The `new` function is a nice wrapper around this function that\n\t/// also creates the ogg reader.\n\t///\n\t/// Please note that this function doesn't work well with async\n\t/// I/O. In order to support this use case, enable the `async_ogg` feature,\n\t/// and use the `HeadersReader` struct instead.\n\tpub fn from_ogg_reader(mut rdr :PacketReader<T>) ->\n\t\t\tResult<Self, VorbisError> {\n\t\tlet ((ident_hdr, comment_hdr, setup_hdr), stream_serial) =\n\t\t\ttry!(read_headers(&mut rdr));\n\t\treturn Ok(OggStreamReader {\n\t\t\trdr,\n\t\t\tpwr : PreviousWindowRight::new(),\n\t\t\tident_hdr,\n\t\t\tcomment_hdr,\n\t\t\tsetup_hdr,\n\t\t\tstream_serial,\n\t\t\tcur_absgp : None,\n\t\t});\n\t}\n\tpub fn into_inner(self) -> PacketReader<T> {\n\t\tself.rdr\n\t}\n\tfn read_next_audio_packet(&mut self) -> Result<Option<Packet>, VorbisError> {\n\t\tloop {\n\t\t\tlet pck = match try!(self.rdr.read_packet()) {\n\t\t\t\tSome(p) => p,\n\t\t\t\tNone => return Ok(None),\n\t\t\t};\n\t\t\tif pck.stream_serial() != self.stream_serial {\n\t\t\t\tif pck.first_in_stream() {\n\t\t\t\t\t// We have a chained ogg file. This means we need to\n\t\t\t\t\t// re-initialize the internal context.\n\t\t\t\t\tlet ident_hdr = try!(read_header_ident(&pck.data));\n\n\t\t\t\t\tlet pck :Packet = try!(self.rdr.read_packet_expected());\n\t\t\t\t\tlet comment_hdr = try!(read_header_comment(&pck.data));\n\n\t\t\t\t\tlet pck :Packet = try!(self.rdr.read_packet_expected());\n\t\t\t\t\tlet setup_hdr = try!(read_header_setup(&pck.data, ident_hdr.audio_channels,\n\t\t\t\t\t\t(ident_hdr.blocksize_0, ident_hdr.blocksize_1)));\n\n\t\t\t\t\t// Update the context\n\t\t\t\t\tself.pwr = PreviousWindowRight::new();\n\t\t\t\t\tself.ident_hdr = ident_hdr;\n\t\t\t\t\tself.comment_hdr = comment_hdr;\n\t\t\t\t\tself.setup_hdr = setup_hdr;\n\t\t\t\t\tself.stream_serial = pck.stream_serial();\n\t\t\t\t\tself.cur_absgp = None;\n\n\t\t\t\t\t// Now, read the first audio packet to prime the pwr\n\t\t\t\t\t// and discard the packet.\n\t\t\t\t\tlet pck = match try!(self.rdr.read_packet()) {\n\t\t\t\t\t\tSome(p) => p,\n\t\t\t\t\t\tNone => return Ok(None),\n\t\t\t\t\t};\n\t\t\t\t\tlet _decoded_pck = try!(read_audio_packet(&self.ident_hdr,\n\t\t\t\t\t\t&self.setup_hdr, &pck.data, &mut self.pwr));\n\t\t\t\t\tself.cur_absgp = Some(pck.absgp_page());\n\n\t\t\t\t\treturn Ok(try!(self.rdr.read_packet()));\n\t\t\t\t} else {\n\t\t\t\t\t// Ignore every packet that has a mismatching stream serial\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn Ok(Some(pck));\n\t\t\t}\n\t\t}\n\t}\n\t/// Reads and decompresses an audio packet from the stream.\n\t///\n\t/// On read errors, it returns Err(e) with the error.\n\t///\n\t/// On success, it either returns None, when the end of the\n\t/// stream has been reached, or Some(packet_data),\n\t/// with the data of the decompressed packet.\n\tpub fn read_dec_packet(&mut self) ->\n\t\t\tResult<Option<Vec<Vec<i16>>>, VorbisError> {\n\t\tlet pck = try!(self.read_dec_packet_generic());\n\t\tOk(pck)\n\t}\n\n\t/// Reads and decompresses an audio packet from the stream (interleaved).\n\t///\n\t/// On read errors, it returns Err(e) with the error.\n\t///\n\t/// On success, it either returns None, when the end of the\n\t/// stream has been reached, or Some(packet_data),\n\t/// with the data of the decompressed packet.\n\t///\n\t/// Unlike `read_dec_packet`, this function returns the\n\t/// interleaved samples.\n\tpub fn read_dec_packet_itl(&mut self) ->\n\t\t\tResult<Option<Vec<i16>>, VorbisError> {\n\t\tlet decoded_pck :InterleavedSamples<_> = match try!(self.read_dec_packet_generic()) {\n\t\t\tSome(p) => p,\n\t\t\tNone => return Ok(None),\n\t\t};\n\t\treturn Ok(Some(decoded_pck.samples));\n\t}\n\n\t/// Reads and decompresses an audio packet from the stream (generic).\n\t///\n\t/// On read errors, it returns Err(e) with the error.\n\t///\n\t/// On success, it either returns None, when the end of the\n\t/// stream has been reached, or Some(packet_data),\n\t/// with the data of the decompressed packet.\n\tpub fn read_dec_packet_generic<S :Samples>(&mut self) ->\n\t\t\tResult<Option<S>, VorbisError> {\n\t\tlet pck = match try!(self.read_next_audio_packet()) {\n\t\t\tSome(p) => p,\n\t\t\tNone => return Ok(None),\n\t\t};\n\t\tself.dec_packet_generic(pck).map(Option::Some)\n\t}\n\n\t#[inline]\n\tpub fn dec_packet_generic<S :Samples>(&mut self, pck :Packet) ->\n\t\t\tResult<S, VorbisError> {\n\t\tlet mut decoded_pck :S = try!(read_audio_packet_generic(&self.ident_hdr,\n\t\t\t&self.setup_hdr, &pck.data, &mut self.pwr));\n\n\t\t// If this is the last packet in the logical bitstream,\n\t\t// we need to truncate it so that its ending matches\n\t\t// the absgp of the current page.\n\t\t// This is what the spec mandates and also the behaviour\n\t\t// of libvorbis.\n\t\tif let (Some(absgp), true) = (self.cur_absgp, pck.last_in_stream()) {\n\t\t\tlet target_length = pck.absgp_page().saturating_sub(absgp) as usize;\n\t\t\tdecoded_pck.truncate(target_length);\n\t\t}\n\t\tif pck.last_in_page() {\n\t\t\tself.cur_absgp = Some(pck.absgp_page());\n\t\t} else if let &mut Some(ref mut absgp) = &mut self.cur_absgp {\n\t\t\t*absgp += decoded_pck.num_samples() as u64;\n\t\t}\n\t\treturn Ok(decoded_pck);\n\t}\n\t/// Skips the given number of samples\n\t///\n\t/// Skips multiple packets without decoding any but the last two, so that\n\t/// the leftover number of samples to skip is lower than the length of the\n\t/// returned packet.\n\t///\n\t/// The function runs a linear skip algorithm which means that instead of\n\t/// logarithmic *seeking*, it inspects each packet for its length, and\n\t/// subtracts the length from the length to skip. This function does no\n\t/// packet decoding until it arrives at the destination, which makes it\n\t/// way cheaper than just decoding all packets.\n\t///\n\t/// The absolute granule position is always increased in whole-package\n\t/// increments.\n\tpub fn skip_samples_linear<S :Samples>(&mut self, to_skip :usize) -> Result<(Option<S>, usize), VorbisError> {\n\t\tlet mut to_skip = to_skip;\n\t\tlet mut last_pck :Option<Packet> = None;\n\t\tlet mut next_pck;\n\n\t\tloop {\n\t\t\tif let Some(p) = try!(self.read_next_audio_packet()) {\n\t\t\t\tnext_pck = p;\n\t\t\t} else {\n\t\t\t\treturn Ok((None, to_skip));\n\t\t\t}\n\t\t\tlet mut sample_cnt = try!(get_decoded_sample_count(&self.ident_hdr, &self.setup_hdr, &next_pck.data));\n\t\t\t// If this is the last packet in the logical bitstream,\n\t\t\t// we need to truncate it so that its ending matches\n\t\t\t// the absgp of the current page.\n\t\t\t// This is what the spec mandates and also the behaviour\n\t\t\t// of libvorbis.\n\t\t\tif let (Some(absgp), true) = (self.cur_absgp, next_pck.last_in_stream()) {\n\t\t\t\tlast_pck = None;\n\t\t\t\tlet target_length = next_pck.absgp_page().saturating_sub(absgp) as usize;\n\t\t\t\tsample_cnt = sample_cnt.min(target_length);\n\t\t\t}\n\t\t\tif to_skip < sample_cnt {\n\t\t\t\t// We reached the end of our search.\n\t\t\t\tif let Some(last_pck) = last_pck {\n\t\t\t\t\tself.pwr = PreviousWindowRight::new();\n\t\t\t\t\tlet _decoded_pck :S = try!(read_audio_packet_generic(&self.ident_hdr,\n\t\t\t\t\t\t&self.setup_hdr, &last_pck.data, &mut self.pwr));\n\t\t\t\t}\n\t\t\t\tlet decoded_pck = try!(self.dec_packet_generic(next_pck));\n\t\t\t\treturn Ok((Some(decoded_pck), to_skip));\n\t\t\t} else {\n\t\t\t\tto_skip -= sample_cnt;\n\t\t\t}\n\t\t\tif let &mut Some(ref mut absgp) = &mut self.cur_absgp {\n\t\t\t\t*absgp += sample_cnt as u64;\n\t\t\t}\n\t\t\tlast_pck = Some(next_pck);\n\t\t}\n\t}\n\n\t/// Returns the stream serial of the current stream\n\t///\n\t/// The stream serial can change in chained ogg files.\n\tpub fn stream_serial(&self) -> u32 {\n\t\tself.stream_serial\n\t}\n\n\t/// Returns the absolute granule position of the last read page.\n\t///\n\t/// In the case of ogg/vorbis, the absolute granule position is given\n\t/// as number of PCM samples, on a per channel basis.\n\tpub fn get_last_absgp(&self) -> Option<u64> {\n\t\tself.cur_absgp\n\t}\n\n\t/// Seeks to the specified absolute granule position, with a page granularity.\n\t///\n\t/// The granularity is per-page, and the obtained position is\n\t/// then <= the seeked absgp.\n\t///\n\t/// In the case of ogg/vorbis, the absolute granule position is given\n\t/// as number of PCM samples, on a per channel basis.\n\tpub fn seek_absgp_pg(&mut self, absgp :u64) -> Result<(), VorbisError> {\n\t\ttry!(self.rdr.seek_absgp(None, absgp));\n\t\t// Reset the internal state after the seek\n\t\tself.cur_absgp = None;\n\t\tself.pwr = PreviousWindowRight::new();\n\t\tOk(())\n\t}\n}\n\n#[cfg(feature = \"async_ogg\")]\n/**\nSupport for async I/O\n\nThis module provides support for asyncronous I/O.\n*/\npub mod async_api {\n\n\tuse super::*;\n\tuse ogg::OggReadError;\n\tuse ogg::reading::async_api::PacketReader;\n\tuse futures::stream::Stream;\n\tuse tokio_io::AsyncRead;\n\tuse futures::{Async, Future, Poll};\n\tuse std::io::{Error, ErrorKind};\n\tuse std::mem::replace;\n\n\t/// Async ready creator utility to read headers out of an\n\t/// ogg stream.\n\t///\n\t/// All functions this struct has are ready to be used for operation with async I/O.\n\tpub struct HeadersReader<T: AsyncRead> {\n\t\tpck_rd :PacketReader<T>,\n\t\tident_hdr :Option<IdentHeader>,\n\t\tcomment_hdr :Option<CommentHeader>,\n\t}\n\timpl<T: AsyncRead> HeadersReader<T> {\n\t\tpub fn new(inner :T) -> Self {\n\t\t\tHeadersReader::from_packet_reader(PacketReader::new(inner))\n\t\t}\n\t\tpub fn from_packet_reader(pck_rd :PacketReader<T>) -> Self {\n\t\t\tHeadersReader {\n\t\t\t\tpck_rd,\n\t\t\t\tident_hdr : None,\n\t\t\t\tcomment_hdr : None,\n\t\t\t}\n\t\t}\n\t}\n\timpl<T: AsyncRead> Future for HeadersReader<T> {\n\t\ttype Item = HeaderSet;\n\t\ttype Error = VorbisError;\n\t\tfn poll(&mut self) -> Poll<Self::Item, Self::Error> {\n\t\t\tmacro_rules! rd_pck {\n\t\t\t\t() => {\n\t\t\t\t\tif let Some(pck) = try_ready!(self.pck_rd.poll()) {\n\t\t\t\t\t\tpck\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Note: we are stealing the Io variant from\n\t\t\t\t\t\t// the ogg crate here which is not 100% clean,\n\t\t\t\t\t\t// but I think in general it is what the\n\t\t\t\t\t\t// read_packet_expected function of the ogg\n\t\t\t\t\t\t// crate does too, and adding our own case\n\t\t\t\t\t\t// to the VorbisError enum that only fires\n\t\t\t\t\t\t// in an async mode is too complicated IMO.\n\t\t\t\t\t\ttry!(Err(OggReadError::ReadError(Error::new(ErrorKind::UnexpectedEof,\n\t\t\t\t\t\t\t\"Expected header packet but found end of stream\"))))\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif self.ident_hdr.is_none() {\n\t\t\t\tlet pck = rd_pck!();\n\t\t\t\tself.ident_hdr = Some(try!(read_header_ident(&pck.data)));\n\t\t\t}\n\t\t\tif self.comment_hdr.is_none() {\n\t\t\t\tlet pck = rd_pck!();\n\t\t\t\tself.comment_hdr = Some(try!(read_header_comment(&pck.data)));\n\t\t\t}\n\t\t\tlet setup_hdr = {\n\t\t\t\tlet ident = self.ident_hdr.as_ref().unwrap();\n\t\t\t\tlet pck = rd_pck!();\n\t\t\t\ttry!(read_header_setup(&pck.data,\n\t\t\t\t\tident.audio_channels, (ident.blocksize_0, ident.blocksize_1)))\n\t\t\t};\n\t\t\tlet ident_hdr = replace(&mut self.ident_hdr, None).unwrap();\n\t\t\tlet comment_hdr = replace(&mut self.comment_hdr, None).unwrap();\n\t\t\tOk(Async::Ready((ident_hdr, comment_hdr, setup_hdr)))\n\t\t}\n\t}\n\t/// Reading ogg/vorbis files or streams\n\t///\n\t/// This is a small helper struct to help reading ogg/vorbis files\n\t/// or streams in that format.\n\t///\n\t/// It only supports the main use case of pure audio ogg files streams.\n\t/// Reading a file where vorbis is only one of multiple streams, like\n\t/// in the case of ogv, is not supported.\n\t///\n\t/// If you need support for this, you need to use the lower level methods\n\t/// instead.\n\tpub struct OggStreamReader<T :AsyncRead> {\n\t\tpck_rd :PacketReader<T>,\n\t\tpwr :PreviousWindowRight,\n\n\t\tpub ident_hdr :IdentHeader,\n\t\tpub comment_hdr :CommentHeader,\n\t\tpub setup_hdr :SetupHeader,\n\n\t\tabsgp_of_last_read :Option<u64>,\n\t}\n\n\timpl<T :AsyncRead> OggStreamReader<T> {\n\t\t/// Creates a new OggStreamReader from the given parameters\n\t\tpub fn new(hdr_rdr :HeadersReader<T>, hdrs :HeaderSet) -> Self {\n\t\t\tOggStreamReader::from_pck_rdr(hdr_rdr.pck_rd, hdrs)\n\t\t}\n\t\t/// Creates a new OggStreamReader from the given parameters\n\t\tpub fn from_pck_rdr(pck_rd :PacketReader<T>, hdrs :HeaderSet) -> Self {\n\t\t\tOggStreamReader {\n\t\t\t\tpck_rd,\n\t\t\t\tpwr : PreviousWindowRight::new(),\n\n\t\t\t\tident_hdr : hdrs.0,\n\t\t\t\tcomment_hdr : hdrs.1,\n\t\t\t\tsetup_hdr : hdrs.2,\n\n\t\t\t\tabsgp_of_last_read : None,\n\t\t\t}\n\t\t}\n\t}\n\n\timpl<T :AsyncRead> Stream for OggStreamReader<T> {\n\t\ttype Item = Vec<Vec<i16>>;\n\t\ttype Error = VorbisError;\n\n\t\tfn poll(&mut self) -> Poll<Option<Vec<Vec<i16>>>, VorbisError> {\n\t\t\tlet pck = match try_ready!(self.pck_rd.poll()) {\n\t\t\t\tSome(p) => p,\n\t\t\t\tNone => return Ok(Async::Ready(None)),\n\t\t\t};\n\t\t\tlet decoded_pck = try!(read_audio_packet(&self.ident_hdr,\n\t\t\t\t&self.setup_hdr, &pck.data, &mut self.pwr));\n\t\t\tself.absgp_of_last_read = Some(pck.absgp_page());\n\t\t\tOk(Async::Ready(Some(decoded_pck)))\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/lib.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n#![cfg_attr(not(cargo_c), forbid(unsafe_code))]\n#![cfg_attr(test, allow(unknown_lints))]\n#![forbid(non_ascii_idents)]\n\n/*!\nA `vorbis` decoder, written in Rust.\n\nIf you \"just\" want to decode `ogg/vorbis` files, take a look into\nthe `inside_ogg` module (make sure you haven't disabled the `ogg` feature).\n\nFor lower level, per-packet usage, you can have a look at the `audio` and `header`\nmodules.\n*/\n\nextern crate byteorder;\nextern crate tinyvec;\n#[cfg(feature = \"ogg\")]\nextern crate ogg;\n#[cfg(feature = \"async_ogg\")]\n#[macro_use]\nextern crate futures;\n#[cfg(feature = \"async_ogg\")]\nextern crate tokio_io;\n\nmacro_rules! try {\n\t($expr:expr) => (match $expr {\n\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t$crate::std::result::Result::Err(err) => {\n\t\t\treturn Err($crate::std::convert::From::from(err));\n\t\t}\n\t})\n}\n\n/*\n// This little thing is very useful.\nmacro_rules! try {\n\t($expr:expr) => (match $expr {\n\t\t$crate::std::result::Result::Ok(val) => val,\n\t\t$crate::std::result::Result::Err(err) => {\n\t\t\tpanic!(\"Panic on Err turned on for debug reasons. Encountered Err: {:?}\", err)\n\t\t}\n\t})\n}\n// */\n\n// The following macros are super useful for debugging\n\nmacro_rules! record_residue_pre_inverse {\n\t($residue_vectors:expr) => {\n// \t\tfor v in $residue_vectors.iter() {\n// \t\t\tfor &re in v {\n// \t\t\t\tprintln!(\"{}\", re);\n// \t\t\t}\n// \t\t}\n\t}\n}\n\nmacro_rules! record_residue_post_inverse {\n\t($residue_vectors:expr) => {\n// \t\tfor v in $residue_vectors.iter() {\n// \t\t\tfor &re in v {\n// \t\t\t\tprintln!(\"{}\", re);\n// \t\t\t}\n// \t\t}\n\t}\n}\n\nmacro_rules! record_pre_mdct {\n\t($audio_spectri:expr) => {\n// \t\tfor v in $audio_spectri.iter() {\n// \t\t\tfor &s in v {\n// \t\t\t\tprintln!(\"{:.5}\", s);\n// \t\t\t}\n// \t\t}\n\t}\n}\n\nmacro_rules! record_post_mdct {\n\t($audio_spectri:expr) => {\n// \t\tfor v in $audio_spectri.iter() {\n// \t\t\tfor &s in v {\n// \t\t\t\tprintln!(\"{:.4}\", s);\n// \t\t\t}\n// \t\t}\n\t}\n}\n\npub mod header;\nmod header_cached;\nmod huffman_tree;\nmod imdct;\n#[cfg(test)]\nmod imdct_test;\npub mod audio;\nmod bitpacking;\n#[cfg(feature = \"ogg\")]\npub mod inside_ogg;\npub mod samples;\n\n#[cfg(feature = \"ogg\")]\n#[doc(no_inline)]\npub use ogg::OggReadError;\n\n#[cfg(cargo_c)]\nmod capi;\n\n#[cfg(cargo_c)]\npub use capi::*;\n\n/// Errors that can occur during decoding\n#[derive(Debug)]\npub enum VorbisError {\n\tBadAudio(audio::AudioReadError),\n\tBadHeader(header::HeaderReadError),\n\t#[cfg(feature = \"ogg\")]\n\tOggError(OggReadError),\n}\n\nimpl std::error::Error for VorbisError {}\n\nimpl std::fmt::Display for VorbisError {\n\tfn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {\n\t\twrite!(fmt, \"{}\", match self {\n\t\t\tVorbisError::BadAudio(_) => \"Vorbis bitstream audio decode problem\",\n\t\t\tVorbisError::BadHeader(_) => \"Vorbis bitstream header decode problem\",\n\t\t\t#[cfg(feature = \"ogg\")]\n\t\t\tVorbisError::OggError(_) => \"Ogg decode problem\",\n\t\t})\n\t}\n}\n\nimpl From<audio::AudioReadError> for VorbisError {\n\tfn from(err :audio::AudioReadError) -> VorbisError {\n\t\tVorbisError::BadAudio(err)\n\t}\n}\n\nimpl From<header::HeaderReadError> for VorbisError {\n\tfn from(err :header::HeaderReadError) -> VorbisError {\n\t\tVorbisError::BadHeader(err)\n\t}\n}\n\n#[cfg(feature = \"ogg\")]\nimpl From<OggReadError> for VorbisError {\n\tfn from(err :OggReadError) -> VorbisError {\n\t\tVorbisError::OggError(err)\n\t}\n}\n\nfn ilog(val :u64) -> u8 {\n\t64 - val.leading_zeros() as u8\n}\n\n#[test]\nfn test_ilog() {\n\t// Uses the test vectors from the Vorbis I spec\n\tassert_eq!(ilog(0), 0);\n\tassert_eq!(ilog(1), 1);\n\tassert_eq!(ilog(2), 2);\n\tassert_eq!(ilog(3), 2);\n\tassert_eq!(ilog(4), 3);\n\tassert_eq!(ilog(7), 3);\n}\n\nfn bit_reverse(n :u32) -> u32 {\n\tn.reverse_bits()\n}\n\n\n#[allow(dead_code)]\nfn print_u8_slice(arr :&[u8]) {\n\tif arr.len() <= 4 {\n\t\tfor a in arr {\n\t\t\tprint!(\"0x{:02x} \", a);\n\t\t}\n\t\tprintln!(\"\");\n\t\treturn;\n\t}\n\tprintln!(\"[\");\n\tlet mut i :usize = 0;\n\twhile i * 4 < arr.len() - 4 {\n\t\tprintln!(\"\\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x},\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);\n\t\ti += 1;\n\t}\n\tmatch arr.len() as i64 - i as i64 * 4 {\n\t\t1 => println!(\"\\t0x{:02x}];\", arr[i * 4]),\n\t\t2 => println!(\"\\t0x{:02x}, 0x{:02x}];\", arr[i * 4], arr[i * 4 + 1]),\n\t\t3 => println!(\"\\t0x{:02x}, 0x{:02x}, 0x{:02x}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),\n\t\t4 => println!(\"\\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),\n\t\tde => panic!(\"impossible value {}\", de),\n\t}\n}\n\n#[allow(dead_code)]\nfn print_u32_slice(arr :&[u32]) {\n\tif arr.len() <= 4 {\n\t\tfor a in arr {\n\t\t\tprint!(\"0x{:02x} \", a);\n\t\t}\n\t\tprintln!(\"\");\n\t\treturn;\n\t}\n\tprintln!(\"[\");\n\tlet mut i :usize = 0;\n\twhile i * 4 < arr.len() - 4 {\n\t\tprintln!(\"\\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x},\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);\n\t\ti += 1;\n\t}\n\tmatch arr.len() as i64 - i as i64 * 4 {\n\t\t1 => println!(\"\\t0x{:08x}];\", arr[i * 4]),\n\t\t2 => println!(\"\\t0x{:08x}, 0x{:08x}];\", arr[i * 4], arr[i * 4 + 1]),\n\t\t3 => println!(\"\\t0x{:08x}, 0x{:08x}, 0x{:08x}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),\n\t\t4 => println!(\"\\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),\n\t\tde => panic!(\"impossible value {}\", de),\n\t}\n}\n\n\n#[allow(dead_code)]\nfn print_f64_slice(arr :&[f64]) {\n\tif arr.len() <= 4 {\n\t\tfor a in arr {\n\t\t\tprint!(\"0x{} \", a);\n\t\t}\n\t\tprintln!(\"\");\n\t\treturn;\n\t}\n\tprintln!(\"[\");\n\tlet mut i :usize = 0;\n\twhile i * 4 < arr.len() - 4 {\n\t\tprintln!(\"\\t{}, {}, {}, {},\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);\n\t\ti += 1;\n\t}\n\tmatch arr.len() as i64 - i as i64 * 4 {\n\t\t1 => println!(\"\\t{}];\", arr[i * 4]),\n\t\t2 => println!(\"\\t{}, {}];\", arr[i * 4], arr[i * 4 + 1]),\n\t\t3 => println!(\"\\t{}, {}, {}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),\n\t\t4 => println!(\"\\t{}, {}, {}, {}];\",\n\t\t\t\tarr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),\n\t\tde => panic!(\"impossible value {}\", de),\n\t}\n}\n"
  },
  {
    "path": "src/samples.rs",
    "content": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2019 est31 <MTest31@outlook.com>\n// and contributors. All rights reserved.\n// Licensed under MIT license, or Apache 2 license,\n// at your option. Please see the LICENSE file\n// attached to this source distribution for details.\n\n/*!\nTraits for sample formats\n*/\n\n/// Trait for a packet of multiple samples\npub trait Samples {\n\tfn num_samples(&self) -> usize;\n\tfn truncate(&mut self, limit :usize);\n\tfn from_floats(floats :Vec<Vec<f32>>) -> Self;\n}\n\nimpl<S :Sample> Samples for Vec<Vec<S>> {\n\tfn num_samples(&self) -> usize {\n\t\tself[0].len()\n\t}\n\tfn truncate(&mut self, limit :usize) {\n\t\tfor ch in self.iter_mut() {\n\t\t\tif limit < ch.len() {\n\t\t\t\tch.truncate(limit);\n\t\t\t}\n\t\t}\n\t}\n\n\tfn from_floats(floats :Vec<Vec<f32>>) -> Self {\n\t\tfloats.into_iter()\n\t\t\t.map(|samples| {\n\t\t\t\tsamples.into_iter()\n\t\t\t\t\t.map(S::from_float)\n\t\t\t\t\t.collect()\n\t\t\t}).collect()\n\t}\n}\n\n/// A packet of multi-channel interleaved samples\npub struct InterleavedSamples<S :Sample> {\n\tpub samples :Vec<S>,\n\tpub channel_count :usize,\n}\n\nimpl<S :Sample> Samples for InterleavedSamples<S> {\n\tfn num_samples(&self) -> usize {\n\t\tself.samples.len() / self.channel_count\n\t}\n\tfn truncate(&mut self, limit :usize) {\n\t\tself.samples.truncate(limit * self.channel_count);\n\t}\n\tfn from_floats(floats :Vec<Vec<f32>>) -> Self {\n\t\tlet channel_count = floats.len();\n\t\t// Note that a channel count of 0 is forbidden\n\t\t// by the spec and the header decoding code already\n\t\t// checks for that.\n\t\tassert!(floats.len() > 0);\n\t\tlet samples_interleaved = if channel_count == 1 {\n\t\t\t// Because decoded_pck[0] doesn't work...\n\t\t\t<Vec<Vec<S>> as Samples>::from_floats(floats).into_iter().next().unwrap()\n\t\t} else {\n\t\t\tlet len = floats[0].len();\n\t\t\tlet mut samples = Vec::with_capacity(len * channel_count);\n\t\t\tfor i in 0 .. len {\n\t\t\t\tfor ref chan in floats.iter() {\n\t\t\t\t\tsamples.push(S::from_float(chan[i]));\n\t\t\t\t}\n\t\t\t}\n\t\t\tsamples\n\t\t};\n\t\tSelf {\n\t\t\tsamples : samples_interleaved,\n\t\t\tchannel_count,\n\t\t}\n\t}\n}\n\n/// Trait representing a single sample\npub trait Sample {\n\tfn from_float(fl :f32) -> Self;\n}\n\nimpl Sample for f32 {\n\tfn from_float(fl :f32) -> Self {\n\t\tfl\n\t}\n}\n\nimpl Sample for i16 {\n\tfn from_float(fl :f32) -> Self {\n\t\tlet fl = fl * 32768.0;\n\t\tif fl > 32767. {\n\t\t\t32767\n\t\t} else if fl < -32768. {\n\t\t\t-32768\n\t\t} else {\n\t\t\tfl as i16\n\t\t}\n\t}\n}\n"
  }
]