Full Code of RustAudio/lewton for AI

master bb2955b71709 cached
27 files
266.3 KB
101.6k tokens
228 symbols
1 requests
Download .txt
Showing preview only (277K chars total). Download the full file or copy to clipboard to get everything.
Repository: RustAudio/lewton
Branch: master
Commit: bb2955b71709
Files: 27
Total size: 266.3 KB

Directory structure:
gitextract_1hjhdekp/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── lewton.yml
├── .gitignore
├── .rustfmt.toml
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE
├── README.md
├── cbindgen.toml
├── dev/
│   └── cmp/
│       ├── Cargo.toml
│       ├── src/
│       │   ├── lib.rs
│       │   └── main.rs
│       └── tests/
│           ├── fuzzed.rs
│           └── vals.rs
├── examples/
│   ├── perf.rs
│   └── player.rs
└── src/
    ├── audio.rs
    ├── bitpacking.rs
    ├── capi.rs
    ├── header.rs
    ├── header_cached.rs
    ├── huffman_tree.rs
    ├── imdct.rs
    ├── imdct_test.rs
    ├── inside_ogg.rs
    ├── lib.rs
    └── samples.rs

================================================
FILE CONTENTS
================================================

================================================
FILE: .editorconfig
================================================
# top-most EditorConfig file
root = true

[*]
indent_style = tab
tab_width = 4
end_of_line=lf
charset=utf-8
trim_trailing_whitespace=true
insert_final_newline=true


================================================
FILE: .github/workflows/lewton.yml
================================================
name: lewton

on: [push, pull_request]

jobs:
  build:

    strategy:
      matrix:
        os: [macOS-latest, ubuntu-latest, windows-latest]
        toolchain: [stable, 1.56.1]

    runs-on: ${{ matrix.os }}

    steps:
    - uses: actions/checkout@master
    - name: Install Rust
      uses: actions-rs/toolchain@v1
      with:
        toolchain: ${{ matrix.toolchain }}
        override: true
    - name: Run no-default-features builds
      env:
        RUSTFLAGS: -D warnings
      run: |
        cargo test --verbose --no-default-features
        cargo doc --verbose --no-default-features
    - name: Run all-features builds
      env:
        RUSTFLAGS: -D warnings
      run: |
        cargo test --verbose --all-features
        cargo doc --verbose --all-features
    - name: Run cmp tests
      env:
        RUSTFLAGS: -D warnings
      if: (matrix.toolchain == '1.56.1') && (matrix.os != 'windows-latest')
      run: |
        sed -i.bak "/^vorb.*/d;s/#v/v/" dev/cmp/Cargo.toml
        cargo update -p vorbis-sys:0.0.8
        cargo test --verbose --release -p cmp


================================================
FILE: .gitignore
================================================
target
*swp
callgrind.out.*
test-assets


================================================
FILE: .rustfmt.toml
================================================
# Note that this rustfmt file only provides rough
# guidelines about how the style should be.
# Right now, rustfmt is not capable to map all
# demands to the code style (yet).

hard_tabs = true
normalize_comments = false
max_width = 120
ideal_width = 100
space_before_type_annotation = true
space_before_bound = false
space_after_type_annotation_colon = false
space_after_bound_colon = true
spaces_around_ranges = true
match_block_trailing_comma = true
match_wildcard_trailing_comma = true
wrap_match_arms = false
fn_brace_style = "PreferSameLine"
item_brace_style = "PreferSameLine"
fn_args_layout = "Block"
where_pred_indent = "Block"
generics_indent = "Block"
struct_lit_style = "Block"
fn_call_style = "Block"
chain_indent = "Block"
take_source_hints = true
trailing_comma = "Vertical"
fn_args_density = "Compressed"
where_density = "Compressed"


================================================
FILE: CHANGELOG.md
================================================
# Changes

## Release 0.10.2 - January 20, 2021

* Updated ogg to 0.8
* Updated tinyvec to 1.0
* Testsuite fixes. Thanks to [@nico-abram](https://github.com/nico-abram) for their help!

## Release 0.10.1 - March 16, 2020

* Removed deprecated Error descriptions
* Swapped smallvec for tinyvec. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the contribution!

## Release 0.10.0 - January 30, 2020

* MSRV increased to 1.36.0. This is mainly because smallvec needs 1.36.0 now.
* Updated to smallvec 1.0. Thanks to [@repi](https://github.com/repi) for the contribution!
* C API via cbingen/cargo-c. Thanks to [@lu-zero](https://github.com/lu-zero) for the contribution!
* Various simplifications in audio.rs. Thanks to [@AnthonyMikh](https://github.com/AnthonyMikh) for the contribution!
* Moved from Travis CI to Github Actions. Thanks to [@Luni-4](https://github.com/Luni-4) for the contribution!
* Adopted a workspace to have a common Cargo.lock file.

## Release 0.9.4 - March 08, 2019

* Added a function to obtain the stream serial from an `OggStreamReader`
* Invalid UTF-8 strings in comment headers are now silently omitted
* Allowed to specify floats as output format
* Fixed multiple bugs on fuzzed inputs

## Release 0.9.3 - October 28, 2018

* Fixed wrongly decoded files. Now, not a single mismatch to libvorbis is left on the xiph and libnogg test vectors (issue [#26](https://github.com/RustAudio/lewton/issues/26))
* Updated ogg to 0.7.0

## Release 0.9.2 - October 07, 2018

* Fixed a wrongly decoded file bug (issue [#24](https://github.com/RustAudio/lewton/issues/24))

## Release 0.9.1 - September 22, 2018

* Performance improvements of about 10%. Thanks to [@GabrielMajeri](https://github.com/GabrielMajeri) for the contribution!
* Fixed some wrongly decoded files
* Fixed some panics on crafted input. Thanks to [@Shnatsel](https://github.com/Shnatsel) for the fuzzing and bug reports.
* Added travis CI

## Release 0.9.0 - August 16, 2018

* Renamed `async` to `async_api` for better edition 2018 compilance
* Updated ogg to 0.6.0
* Expanded test suite to include xiph test vectors
* Support for chained files

## Release 0.8.0 - February 7, 2018

* Removed unused error enum variant
* Pub used OggReadError so that people can match on its variants without needing to depend on the Ogg crate
* Used min instead of residue_begin/residue_end directly. See also [the PR](https://github.com/xiph/vorbis/pull/35) that modified the vorbis spec accordingly.

## Release 0.7.0 - October 24, 2017

* Removed all uses of unsafe in return of making Rust 1.20 required

## Release 0.6.2 - June 18, 2017

* Exposed blockize_0 and blocksize_1 in the public API
  of the ident header again, so that lewton can be used without ogg encapsulation.

## Release 0.6.1 - June 8, 2017

* Fix a doc link

## Release 0.6.0 - June 8, 2017

* Made parts of the API that are not intended for the public crate local
* Added seeking support with a granularity of pages
* Updated to ogg to 0.5.0
* The async support now doesn't need unstable features any more, and bases on tokio

## Release 0.5.2 - May 13, 2017

* Removed two unused macros to prevent warnings about them

## Release 0.5.1 - April 30, 2017

* Bugfix to work on newest Rust nightly/beta
* Bugfix to work with the alto crate instead of openal-rs which has been yanked
* Bugfix in the player example for duration calculation

## Release 0.5 - February 15, 2017

* New, more convenient, constructor for OggStreamReader.
* Updated to Byteorder 1.0.

## Release 0.4.1 - November 17, 2016

* Fixed a panic issue with reading huffman trees.

## Release 0.4 - October 4, 2016

* Updated ogg.
* Made the `inside_ogg` API own the reader.

## Release 0.3 - October 4, 2016

* Added support for floor 0. It is not used in practice anymore,
  but now all features of the vorbis format are supported.
* Improved the API for reading decoded packets.
* Fixed a bug in comment header parsing.
* Various minor simplifications.
* Improved the cmp tool. You can now compare our output to libvorbis
  with `cargo test --release -- --nocapture`,
  and our speed with `cargo run --release bench`.

## Release 0.2 - September 13, 2016

* Improved speed by about 20%.
* Added async ready API to the `inside_ogg` module to work with async IO.
  Still behind a feature as it relies on the unstable [specialisation feature](https://github.com/rust-lang/rust/issues/31844).
* Removed parts of the API that were irrelevant to users of the crate.
  This gives a better overview for our users.
  Unfortunately due to [pub(crate) not being stable yet](https://github.com/rust-lang/rust/issues/32409),
  not all parts of the API could have been made private.
* Examples are CC-0 now, this should ease adoption.
* Documentation improvements
* Implemented a tool to compare our speed and output with libvorbis.
  To see how correct this crate is, cd to `dev/cmp` and do `cargo run --release vals /path/to/test_file.ogg`.
  For speed tests, swap "vals" with "perf".

## Release 0.1 - September 1, 2016

Initial release.










================================================
FILE: Cargo.toml
================================================
[workspace]
members = ["dev/cmp"]

[package]
name = "lewton"
version = "0.10.2"
authors = ["est31 <MTest31@outlook.com>"]
description = "Pure Rust vorbis decoder"
license = "MIT OR Apache-2.0"
repository = "https://github.com/RustAudio/lewton"
keywords = ["ogg", "vorbis", "decoder", "audio"]
categories = ["compression", "multimedia::audio", "multimedia::encoding"]
documentation = "https://docs.rs/lewton"
readme = "README.md"
edition = "2015"
rust-version = "1.56.0"

[features]
default = ["ogg"]
async_ogg = ["ogg", "ogg/async", "futures", "tokio-io"]
capi = []

[[example]]
name = "perf"
required-features = ["ogg"]

[[example]]
name = "player"
required-features = ["ogg"]

[dependencies]
byteorder = "1.0"
tinyvec = { version = "1.0", features = ["alloc"] }
ogg = { version = "0.8", optional = true }
tokio-io = { version = "0.1", optional = true }
futures = { version = "0.1", optional = true }

[dev-dependencies]
ogg = "0.8"
alto = "3"

[package.metadata.docs.rs]
features = ["async_ogg"]

[lib]
name = "lewton"


================================================
FILE: LICENSE
================================================
Copyright (c) 2016 est31 <MTest31@outlook.com> and contributors

Licensed under MIT or Apache License 2.0,
at your option.

The full list of contributors can be obtained by looking
at the VCS log (originally, this crate was git versioned,
there you can do "git shortlog -sn" for this task).

MIT License
-----------

The MIT License (MIT)

Copyright (c) 2016 est31 <MTest31@outlook.com> and contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.



Apache License, version 2.0
---------------------------
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS


================================================
FILE: README.md
================================================
# lewton

[![docs](https://docs.rs/lewton/badge.svg)](https://docs.rs/crate/lewton)
[![crates.io](https://img.shields.io/crates/v/lewton.svg)](https://crates.io/crates/lewton)
[![dependency status](https://deps.rs/repo/github/rustaudio/lewton/status.svg)](https://deps.rs/repo/github/rustaudio/lewton)

Vorbis decoder written in pure Rust.

To give the decoder a try, you can do:
```sh
cargo run --example player /path/to/your/audio_file.ogg
```
It will then play back the audio.

If you want to know how to use this crate, look at the examples folder.

This crate has a low level API for per-packet decoding in the `audio` and `header` modules,
and a high level API for ogg/vorbis streams in the `inside_ogg` module.

Some parts were created with help from the public domain
[stb_vorbis](http://nothings.org/stb_vorbis/) decoder implementation.

The minimum required Rust version is 1.56.

## Use of unsafe

The entire library uses not a single line of unsafe code.
In fact, lib.rs contains the `#![forbid(unsafe_code)]` directive.

## About the history of this crate

I started to work on this crate in December 2015.
The goal was to learn more about Rust and audio processing,
while also delivering something useful to the Rust ecosystem.

I've tried not to look into the libvorbis implementation,
as then I'd have to first abide the BSD license, and second
as I didn't want this crate to become "just" a translation
from C to Rust. Instead I wanted this crate to base on the
spec only, so that I'd learn more about how vorbis worked.

The only time I did look into the libvorbis implementation
was to look up the implementation of a function needed by
the ogg crate (the CRC function), which is why that crate
is BSD licensed, and attributes the authors.
This crate however contains no code, translated or
otherwise, from the libvorbis implementation.

After some time I realized that without any help of a working
implementation progress would become too slow.

Therefore, I've continued to work with the public domain
`stb_vorbis` implementation and used some of its
code (most prominently for the imdct algorithm) to
translate it to rust. I've also used it for debugging by
comparing its outputs with mine.

Most of this crate however was created by reading the spec
only.

## Use from C
**lewton** provides a C-compatible set of library, header and pkg-config file.

To build and install it you can use [cargo-c](https://crates.io/crates/cargo-c):

```sh
cargo install cargo-c
cargo cinstall --release --destdir /tmp/lewton
sudo cp -a /tmp/lewton/* /
```

## License

Licensed under Apache 2 or MIT (at your option). For details, see the [LICENSE](LICENSE) file.

All examples inside the `examples/` folder are licensed under the
[CC-0](https://creativecommons.org/publicdomain/zero/1.0/) license.

### License of your contributions

Unless you explicitly state otherwise, any contribution intentionally submitted for
inclusion in the work by you, as defined in the Apache-2.0 license,
shall be dual licensed / CC-0 licensed as above, without any additional terms or conditions.


================================================
FILE: cbindgen.toml
================================================
header = "// SPDX-License-Identifier: MIT OR Apache-2.0"
sys_includes = ["stddef.h", "stdint.h", "stdlib.h"]
no_includes = true
include_guard = "LEWTON_LEWTON_H"
tab_width = 4
style = "Type"
language = "C"


================================================
FILE: dev/cmp/Cargo.toml
================================================
[package]
name = "cmp"
publish = false
version = "0.1.0"
license = "MIT OR Apache-2.0"
authors = ["est31 <MTest31@outlook.com>"]
edition = "2015"

[dependencies]
lewton = { path = "../../" }
vorbis = "0.1"
# Workaround for test failure.
# Apply branch of this PR: https://github.com/tomaka/vorbis-rs/pull/20
#vorbis = { git = 'https://github.com/roderickvd/vorbis-rs', branch = 'fix-ub-panic' }
test-assets = "0.2"


================================================
FILE: dev/cmp/src/lib.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016-2017 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

extern crate lewton;
extern crate vorbis;
extern crate test_assets;

use std::fs::File;

use lewton::inside_ogg::*;
use lewton::header::{IdentHeader, CommentHeader, SetupHeader};
use std::time::{Duration, Instant};
use std::io::{Cursor, Read, Seek};

use vorbis::Decoder as NativeDecoder;

pub fn cmp_perf(file_path :&str) -> (Duration, Duration, usize) {
	macro_rules! try {
		($expr:expr) => (match $expr {
			$crate::std::result::Result::Ok(val) => val,
			$crate::std::result::Result::Err(err) => {
				panic!("Error: {:?}", err)
			}
		})
	}

	// Read the file to memory to create fairer playing ground
	let mut f = try!(File::open(file_path));
	let mut file_buf = Vec::new();
	try!(f.read_to_end(&mut file_buf));

	let r_n = Cursor::new(&file_buf);
	let start_native_decode = Instant::now();
	let dec = try!(NativeDecoder::new(r_n));
	let mut native_it = dec.into_packets();
	loop {
		try!(match native_it.next() {
			Some(v) => v,
			None => break,
		});
	}
	let native_decode_duration = Instant::now() - start_native_decode;

	let mut n = 0;
	let r_r = Cursor::new(&file_buf);
	let start_decode = Instant::now();
	let mut ogg_rdr = try!(OggStreamReader::new(r_r));

	// Reading and discarding the first empty packet
	// The native decoder does this itself.
	try!(ogg_rdr.read_dec_packet());

	while let Some(_) = try!(ogg_rdr.read_dec_packet()) {
		n += 1;
	}
	let decode_duration = Instant::now() - start_decode;
	return (decode_duration, native_decode_duration, n);
}

pub fn cmp_file_output(file_path :&str) -> (usize, usize) {
	macro_rules! try {
		($expr:expr) => (match $expr {
			$crate::std::result::Result::Ok(val) => val,
			$crate::std::result::Result::Err(err) => {
				panic!("Error: {:?}", err)
			}
		})
	}
	let f = try!(File::open(&file_path));
	let f_2 = try!(File::open(&file_path));
	try!(cmp_output(f, f_2, |u, v, _, _, _, _, _| (u, v)))
}

pub fn cmp_output<R :Read + Seek, T, F :Fn(usize, usize, usize,
		bool,
		&IdentHeader, &CommentHeader, &SetupHeader)->T>(
		rdr :R, rdr_2 :R, f :F) -> Result<T, String> {
	macro_rules! try {
		($expr:expr) => (match $expr {
			$crate::std::result::Result::Ok(val) => val,
			$crate::std::result::Result::Err(err) => {
				return Err(format!("{:?}", err))
			}
		})
	}
	let f_n = rdr;
	let f_r = rdr_2;

	let dec = try!(NativeDecoder::new(f_n));

	let mut ogg_rdr = try!(OggStreamReader::new(f_r));
	let stream_serial = ogg_rdr.stream_serial();

	// Now the fun starts..
	let mut native_it = dec.into_packets();
	let mut n = 0;

	// Reading and discarding the first empty packet
	// The native decoder does this itself.
	try!(ogg_rdr.read_dec_packet());

	let mut pcks_with_diffs = 0;

	// This parameter is useful when we only want to check whether the
	// actually returned data are the same, regardless of where the
	// two implementations put packet borders.
	// Of course, when debugging bugs which modify the size of packets
	// you usually want to set this flag to false so that you don't
	// suffer from the "carry over" effect of errors.
	let ignore_packet_borders :bool = true;

	let mut native_dec_data = Vec::new();
	let mut dec_data = Vec::new();

	let mut total_sample_count = 0;

	let mut chained_ogg_file = false;
	loop {
		n += 1;

		let mut native_decoded = try!(match native_it.next() { Some(v) => v,
			None => break,});
		native_dec_data.extend_from_slice(&mut native_decoded.data);
		let mut pck_decompressed = match try!(ogg_rdr.read_dec_packet_itl()) {
			Some(v) => v,
			None => break, // TODO tell calling code about this condition
		};

		// Asserting some very basic things:
		assert_eq!(native_decoded.rate, ogg_rdr.ident_hdr.audio_sample_rate as u64);
		assert_eq!(native_decoded.channels, ogg_rdr.ident_hdr.audio_channels as u16);

		total_sample_count += pck_decompressed.len();
		if stream_serial != ogg_rdr.stream_serial() {
			// Chained ogg file
			chained_ogg_file = true;
		}

		// Fill dec_data with stuff from this packet

		dec_data.extend_from_slice(&mut pck_decompressed);

		let mut diffs = 0;
		for (s,n) in dec_data.iter().zip(native_dec_data.iter()) {
			let diff = *s as i32 - *n as i32;
			// +- 2 deviation is allowed.
			if diff.abs() > 2 {
				diffs += 1;
			}
		}

		let native_dec_len = native_dec_data.len();
		let dec_len = dec_data.len();

		if diffs > 0 || (!ignore_packet_borders && dec_len != native_dec_len) {
			/*
			print!("Differences found in packet no {}... ", n);
			print!("ours={} native={}", dec_len, native_dec_len);
			println!(" (diffs {})", diffs);
			*/
			pcks_with_diffs += 1;
		}

		if ignore_packet_borders {
			native_dec_data.drain(..std::cmp::min(native_dec_len, dec_len));
			dec_data.drain(..std::cmp::min(native_dec_len, dec_len));
		} else {
			native_dec_data.truncate(0);
			dec_data.truncate(0);
		}
	}
	return Ok(f(pcks_with_diffs, n, total_sample_count,
		chained_ogg_file,
		&ogg_rdr.ident_hdr, &ogg_rdr.comment_hdr, &ogg_rdr.setup_hdr));
}

/// Like try, but performs an action if an "expected" error
/// is intercepted
#[macro_export]
macro_rules! try_expected {
	($expr:expr, $expected:pat, $action:tt) => (match $expr {
		Ok(val) => val,
		Err($expected) => {
			$action
		},
		Err(e) => {
			panic!("Unexpected error: {:?}\nExpected: {:?}", e, stringify!($type));
		},
	})
}

/// Ensures that a file is malformed and returns an error,
/// but doesn't panic or crash or anything of the like
#[macro_export]
macro_rules! ensure_malformed {
	($name:expr, $expected:pat) => {{
		use std::fs::File;
		use lewton::inside_ogg::OggStreamReader;
		// Read the file to memory
		let f = File::open(format!("test-assets/{}", $name)).unwrap();
		if let Some(mut ogg_rdr) = try_expected!(OggStreamReader::new(f).map(|v| Some(v)), $expected, None) {
			loop {
				match try_expected!(ogg_rdr.read_dec_packet_itl(), $expected, break) {
					Some(_) => (),
					None => panic!("File {} decoded without errors", $name),
				};
			}
		}
	}}
}

/// Ensures that a file decodes without errors
#[macro_export]
macro_rules! ensure_okay {
	($name:expr) => {{
		use std::fs::File;
		use lewton::inside_ogg::OggStreamReader;
		// Read the file to memory
		let f = File::open(format!("test-assets/{}", $name)).unwrap();
		if let Some(mut ogg_rdr) = OggStreamReader::new(f).map(|v| Some(v)).unwrap() {
			loop {
				match ogg_rdr.read_dec_packet_itl().unwrap() {
					Some(_) => (),
					None => break,
				};
			}
		}
	}}
}

use self::test_assets::TestAssetDef;

pub fn get_asset_defs() -> [TestAssetDef; 6] {
	return [
		TestAssetDef {
			filename : format!("bwv_1043_vivace.ogg"),
			hash : format!("839249e46220321e2bbb1106e30d0bef4acd800d3827a482743584f313c8c671"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/bwv_1043_vivace.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("bwv_543_fuge.ogg"),
			hash : format!("c5de55fe3613a88ba1622a1c931836c0af5e9bf3afae951418a07975a16e7421"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/bwv_543_fuge.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("maple_leaf_rag.ogg"),
			hash : format!("f66f18de6bc79126f13d96831619d68ddd56f9527e50e1058be0754b479ee350"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/maple_leaf_rag.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("hoelle_rache.ogg"),
			hash : format!("bbdf0a8d4c151aee5a21fb71ed86894b1aae5c7dba9ea767f7af6c0f752915c2"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/wiki/hoelle_rache.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("thingy-floor0.ogg"),
			hash : format!("02b9e94764db30b876964eba2d0a813dedaecdbfa978a13dc9cef9bdc1f4e9ee"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/thingy-floor0.ogg"),
		},
		TestAssetDef {
			filename : format!("audio_simple_err.ogg"),
			hash : format!("1b97b2b151b34f1ca6868aa0088535792252aa5c7c990e1de9eedd6a33d3c0dd"),
			url : format!("https://github.com/RustAudio/lewton/files/1543593/audio_simple_err.zip"),
		},
	];
}

#[allow(unused)]
pub fn get_libnogg_asset_defs() -> [TestAssetDef; 32] {
	return [
		TestAssetDef {
			filename : format!("6-mode-bits-multipage.ogg"),
			hash : format!("e68f06c58a8125933d869d4c831ee298500b1894ab27dc4841f075c104093c27"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6-mode-bits-multipage.ogg"),
		},
		TestAssetDef {
			filename : format!("6-mode-bits.ogg"),
			hash : format!("48ec7d1b3284ea8cdb9a3511f4f1dd4d8170be9482dd7c0e8edb49802318e1c8"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6-mode-bits.ogg"),
		},
		TestAssetDef {
			filename : format!("6ch-all-page-types.ogg"),
			hash : format!("c965f1f03be8af3869d22fcad41bbde0111ba18748f7c9b27fb46e4a33b857cd"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-all-page-types.ogg"),
		},
		TestAssetDef {
			filename : format!("6ch-long-first-packet.ogg"),
			hash : format!("7ac5d89b9cc69762dd191d17778b0625462d4a2c5488d10e8aef6a77e990c7f7"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-long-first-packet.ogg"),
		},
		TestAssetDef {
			filename : format!("6ch-moving-sine-floor0.ogg"),
			hash : format!("95443ad7c16f3dc7f66ce34aeb3ec90f14fb717c79326e8f3c92826f5c0606e1"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-moving-sine-floor0.ogg"),
		},
		TestAssetDef {
			filename : format!("6ch-moving-sine.ogg"),
			hash : format!("05dae404fc266671598aaf2fd55f52d563e7f26631abbd3487cc9b63d458500d"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/6ch-moving-sine.ogg"),
		},
		TestAssetDef {
			filename : format!("bad-continued-packet-flag.ogg"),
			hash : format!("8c93b1ec92746b4c9eb8c855e65218f14cd8c3024ddea5b3264c8a66fee7d6ee"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bad-continued-packet-flag.ogg"),
		},
		TestAssetDef {
			filename : format!("bitrate-123.ogg"),
			hash : format!("8cbb82b8eab2e4d4115b62f62323c85d05e2352519677996d7a1e53c01ebb436"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-123.ogg"),
		},
		TestAssetDef {
			filename : format!("bitrate-456-0.ogg"),
			hash : format!("2ae12b963c333164f1fbbbf4fc75bc9aa6b5b4289a9791ba9a3a7c275d725571"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-456-0.ogg"),
		},
		TestAssetDef {
			filename : format!("bitrate-456-789.ogg"),
			hash : format!("326bb289c1dcc4f79ee007199a8124dd14bfea4a1f7fb94f9c7f9394c0b53584"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/bitrate-456-789.ogg"),
		},
		TestAssetDef {
			filename : format!("empty-page.ogg"),
			hash : format!("51010e14b84dee562b76d3a4ddb760d4b3a740d78714b11b6307e2de73ee6d48"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/empty-page.ogg"),
		},
		TestAssetDef {
			filename : format!("large-pages.ogg"),
			hash : format!("53b63f9661ddf726bd0b9d1933b7fe54ef10248742354ff215b294f34ac0aec0"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/large-pages.ogg"),
		},
		TestAssetDef {
			filename : format!("long-short.ogg"),
			hash : format!("96a166446ee171f9df3b7a4701567d19e52d8cfc593e17ca4f8697dde551de63"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/long-short.ogg"),
		},
		TestAssetDef {
			filename : format!("noise-6ch.ogg"),
			hash : format!("879ab419c0a848b0d17b1d6b9d8557c4cec35ffb0d973371743eeee70c6f7e17"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/noise-6ch.ogg"),
		},
		TestAssetDef {
			filename : format!("noise-stereo.ogg"),
			hash : format!("53c9e52bf47f89d292644e4cd467da70c49709fdcc7a2c99d171b4e1883a0499"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/noise-stereo.ogg"),
		},
		TestAssetDef {
			filename : format!("partial-granule-position.ogg"),
			hash : format!("d42765b76989a74fc9071d082409a34e9a4c603eecb51b253d4d026a9751580e"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/partial-granule-position.ogg"),
		},
		TestAssetDef {
			filename : format!("sample-rate-max.ogg"),
			hash : format!("c758248cdc2d2ed67ed80f27e8436565fd5b94c5c662a88ab9a5fabd6d23ff04"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sample-rate-max.ogg"),
		},
		TestAssetDef {
			filename : format!("single-code-2bits.ogg"),
			hash : format!("ee1eb710f37709fea87d1fac6cdb6ab86012497c50dae58d237b6607165656b9"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-2bits.ogg"),
		},
		TestAssetDef {
			filename : format!("single-code-nonsparse.ogg"),
			hash : format!("9fbbbe8ba4988d8362a66f4252fe8f528e41ac659db23f377a9166bba843bb7b"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-nonsparse.ogg"),
		},
		TestAssetDef {
			filename : format!("single-code-ordered.ogg"),
			hash : format!("27e53ee98f2773405b98f6ad402aad2d0be3d3fd7439acab720f46c73957bc93"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-ordered.ogg"),
		},
		TestAssetDef {
			filename : format!("single-code-sparse.ogg"),
			hash : format!("3327a0eb7287bc2df2a10932446930c9da6fa3383b0a63a81cfd04f832e160a6"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/single-code-sparse.ogg"),
		},
		TestAssetDef {
			filename : format!("sketch008-floor0.ogg"),
			hash : format!("64fc1efe12609a0544448021c730c2832a758637982a4698a138f138a1417b5c"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch008-floor0.ogg"),
		},
		TestAssetDef {
			filename : format!("sketch008.ogg"),
			hash : format!("d0b34d94a5379edc6eb633743ecd187d81b02e5354fed989f35320ecfd32be71"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch008.ogg"),
		},
		TestAssetDef {
			filename : format!("sketch039.ogg"),
			hash : format!("c595bec5d9bad0103527f779dba13837743866c15ff5ad7aeedc6dab49516d9a"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/sketch039.ogg"),
		},
		TestAssetDef {
			filename : format!("split-packet.ogg"),
			hash : format!("e5e5598845d733a1efaeb258a6c07563af8dd30204117044d25df13cd2944e0e"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/split-packet.ogg"),
		},
		TestAssetDef {
			filename : format!("square-interleaved.ogg"),
			hash : format!("305a703187f5ad84facbf5b8990007cfe93d4035e3efb9f86014967604374356"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-interleaved.ogg"),
		},
		TestAssetDef {
			filename : format!("square-multipage.ogg"),
			hash : format!("691988c4fefe850dd265fd8c91f2e90c92f94578ce18c8005b40e88277dc26c9"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-multipage.ogg"),
		},
		TestAssetDef {
			filename : format!("square-stereo.ogg"),
			hash : format!("b2eb353cdd9ddd3f809647474e1a8bff6913e28b53cac52a54906f7ff203501f"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-stereo.ogg"),
		},
		TestAssetDef {
			filename : format!("square-with-junk.ogg"),
			hash : format!("51ede72de15b2998cf8de6dd3f57a6abc280f9278d775f0f5fec2d2679e341b6"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square-with-junk.ogg"),
		},
		TestAssetDef {
			filename : format!("square.ogg"),
			hash : format!("31c9fa7d2f374ebf9ffc1c21e95b8369c2ced3ae230151c00208613ca308d812"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/square.ogg"),
		},
		// Omit thingy-floor0.ogg
		TestAssetDef {
			filename : format!("thingy.ogg"),
			hash : format!("646f05235723aa09e69e123c73560ffb753f9ffe00e3c54b99f8f0c1cd583707"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/thingy.ogg"),
		},
		TestAssetDef {
			filename : format!("zero-length.ogg"),
			hash : format!("aa71c87218f6dec51383110bc1b77d204bbb21f7867e2cc8283042417522b330"),
			url : format!("http://achurch.org/hg/libnogg/raw-file/tip/tests/data/zero-length.ogg"),
		},
	];
}

#[allow(unused)]
pub fn get_xiph_asset_defs_1() -> [TestAssetDef; 5] {
	return [
		TestAssetDef {
			filename : format!("1.0-test.ogg"),
			hash : format!("9a882710314bcc1d2b4cdefb7f89911f4375acd1feb9e64a12eca9f7202377d3"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/1.0-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("1.0.1-test.ogg"),
			hash : format!("8c9423e00826d6d2457d78c09d6e2a94bcdf9216af796bb22a4c4f450c2e72bb"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/1.0.1-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("48k-mono.ogg"),
			hash : format!("f51459d9bdd04ca3ec6f6732b8a01efcdc83e5c6fc79c7d5347527bfd4948e9e"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/48k-mono.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("beta3-test.ogg"),
			hash : format!("7fc791a4d5a0d3b7cef2448093ccf2ae54600acc81667be90c6b209c366c32ea"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/beta3-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("beta4-test.ogg"),
			hash : format!("bc367c0d4dcdbf1f0a2f81abf74cc52c8f0ab8366d150a75830782ca2dba080a"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/beta4-test.ogg?raw=true"),
		},
	];
}

#[allow(unused)]
pub fn get_xiph_asset_defs_2() -> [TestAssetDef; 5] {
	return [
		TestAssetDef {
			filename : format!("bimS-silence.ogg"),
			hash : format!("e2a38871d390ed651faf0fec5253a6873530da4f2503d85021c99325dfd23813"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/bimS-silence.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("chain-test1.ogg"),
			hash : format!("d9c37533a1f456d2a996755a43d112ef46b6ef953319913907bc79f1c014d79e"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test1.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("chain-test2.ogg"),
			hash : format!("5b5bf834e93e9a93b7114be084161e972f33d2031963518492ba2c91dc4418a7"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test2.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("chain-test3.ogg"),
			hash : format!("ed039ba775d1b31e805d26d6413a3ef2c6663bf4c5ea47ce1462f8f23c84d8dc"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/chain-test3.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("highrate-test.ogg"),
			hash : format!("0942c88369f84b125388cc8437575b66d67bc97baaeeb997b6602144821509df"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/highrate-test.ogg?raw=true"),
		},
	];
}

#[allow(unused)]
pub fn get_xiph_asset_defs_3() -> [TestAssetDef; 5] {
	return [
		TestAssetDef {
			filename : format!("lsp-test.ogg"),
			hash : format!("ad1b07b68576ae2c85178475ef3607e1a96c09e96296cae83ee7a9726f8311eb"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("lsp-test2.ogg"),
			hash : format!("7b00f893a93071bdf243b8a22c1758a6ab09c1ab8eee89ca21659d98ec0f53ea"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test2.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("lsp-test3.ogg"),
			hash : format!("7a5c4064fc31285f6fea0b2424a0d415a8b18ef13d1aa1ef931a429ab9a593d1"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test3.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("lsp-test4.ogg"),
			hash : format!("cb0b28931dfc8ef8b2d320f3028fab548171e7c6e94006f0c23532478a8d3596"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/lsp-test4.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("mono.ogg"),
			hash : format!("d8abca95445a07186c9a158d4f573f38918985dd2498a9bc8d1811bd72fe1d1a"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/mono.ogg?raw=true"),
		},
	];
}

#[allow(unused)]
pub fn get_xiph_asset_defs_4() -> [TestAssetDef; 7] {
	return [
		TestAssetDef {
			filename : format!("moog.ogg"),
			hash : format!("bd5b51bb1d6855e0e990e3ebdd230fc16265407809bd6db44aea691ada498943"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/moog.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("one-entry-codebook-test.ogg"),
			hash : format!("789b5146f2a7c0864a228ee4a870606a32c4169e22097be65129623705c54749"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/one-entry-codebook-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("out-of-spec-blocksize.ogg"),
			hash : format!("0970e66291744815f2ca0dec7523f5bbc112907c5c75978a0f91d3b0ed6f03b2"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/out-of-spec-blocksize.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("rc1-test.ogg"),
			hash : format!("ccfac6ac7c75615bec0632b94bcf088c027c0b112cd136c997d04f037252cd3d"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc1-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("rc2-test.ogg"),
			hash : format!("4adcda786dfeea4188d7b1df35571dbe29c687f2d1cac680ed115353abfe1637"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc2-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("rc2-test2.ogg"),
			hash : format!("24ade471eefe1c7642f73a6810e56266b34c2d7d30a3b5ad05a34c098128226c"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc2-test2.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("rc3-test.ogg"),
			hash : format!("edd984e84c7c2a59af7801f3e8d2db11a6619134fd8d0274d1289e70bf60cde7"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/rc3-test.ogg?raw=true"),
		},
	];
}

#[allow(unused)]
pub fn get_xiph_asset_defs_5() -> [TestAssetDef; 5] {
	return [
		TestAssetDef {
			filename : format!("singlemap-test.ogg"),
			hash : format!("50d8077608a4192b8f8505aec0217be8b6c25def4068899afc19c17f30e1d521"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/singlemap-test.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("sleepzor.ogg"),
			hash : format!("01c67ecaf7a58b5ac5f1fe3bd060b5d61536595e97927a1b1cf0129a62b5cfcf"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/sleepzor.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("test-short.ogg"),
			hash : format!("183510552403021fb90ce43796fcc88e16c8bb4ae5d0d72a316b8e51afc395fa"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/test-short.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("test-short2.ogg"),
			hash : format!("6bd3f59e0fa77904edd35c73dadd6558e2a36d78c9d7bc5db223862bf092fcc2"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/test-short2.ogg?raw=true"),
		},
		TestAssetDef {
			filename : format!("unused-mode-test.ogg"),
			hash : format!("e27ae6fc2f7c0037c28328801c46d966abcee3050e3ebd40bf097f7986f50f94"),
			url : format!("https://github.com/RustAudio/lewton-test-assets/blob/master/xiph/unused-mode-test.ogg?raw=true"),
		},
	];
}

#[allow(unused)]
/// Regression tests for bugs obtained by fuzzing
///
/// The test files are licensed under CC-0:
/// * https://github.com/RustAudio/lewton/issues/33#issuecomment-419640709
/// * http://web.archive.org/web/20180910135020/https://github.com/RustAudio/lewton/issues/33
pub fn get_fuzzed_asset_defs() -> [TestAssetDef; 12] {
	return [
		TestAssetDef {
			filename : format!("27_really_minimized_testcase_crcfix.ogg"),
			hash : format!("83f6d6f36ae926000f064007e79ef7c45ed561e49223d9b68f980d264050d683"),
			url : format!("https://github.com/RustAudio/lewton/files/2363013/27_really_minimized_testcase_crcfix.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("32_minimized_crash_testcase.ogg"),
			hash : format!("644170ccc3e48f2e2bf28cadddcd837520df09671c3d3d991b128b9fdb281da6"),
			url : format!("https://github.com/RustAudio/lewton/files/2363080/32_minimized_crash_testcase.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("33_minimized_panic_testcase.ogg"),
			hash : format!("4812e725d7c6bdb48e745b4e0a396efc96ea5cb30e304cf9710dadda3d963171"),
			url : format!("https://github.com/RustAudio/lewton/files/2363173/33_minimized_panic_testcase.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("35_where_did_my_memory_go_repacked.ogg"),
			hash : format!("2f202e71ca0440a2de4a15443beae9d3230e81e47bc01d29929fc86ee731887c"),
			url : format!("https://github.com/RustAudio/lewton/files/2889595/35_where-did-my-memory-go-repacked.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-42-sample009.ogg"),
			hash : format!("7e3d7fd6d306cd1c1704d0586b4e62cc897c499e3ffc1911f62ec0fc3a062871"),
			url : format!("https://github.com/RustAudio/lewton/files/2905014/bug-42-sample009.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-42-sample012.ogg"),
			hash : format!("8d92c4359bbe987b77459f309859b6bba0a11724e71fd5e81873c597ec71d857"),
			url : format!("https://github.com/RustAudio/lewton/files/2905017/bug-42-sample012.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-42-sample015.ogg"),
			hash : format!("274c17222d7cfc1044d2fee3e60377eac87f5ee8d952eeaf3d636b016b1db7d3"),
			url : format!("https://github.com/RustAudio/lewton/files/2905018/bug-42-sample015.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-42-sample016.ogg"),
			hash : format!("ab02fd55a275b1ec0c6c56a667834231bf34b3a79038f43196d1015c1555e535"),
			url : format!("https://github.com/RustAudio/lewton/files/2905019/bug-42-sample016.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-42-sample029.ogg"),
			hash : format!("1436fff4d8fa61ff2b22ffd021c2bd80f072556b8b58cfc72fdfc0434efd9a24"),
			url : format!("https://github.com/RustAudio/lewton/files/2905020/bug-42-sample029.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-44-sample059.ogg"),
			hash : format!("4c1452e387a64090465132724a83f02846457336fa58ddc6ee9c6df598d756c0"),
			url : format!("https://github.com/RustAudio/lewton/files/2922511/bug-44-sample059.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-44-sample060.ogg"),
			hash : format!("b8bd42831a8922c4c78ff1ea5b42ecbb874135ba7e7fcd60c4fff7a419d857a4"),
			url : format!("https://github.com/RustAudio/lewton/files/2922512/bug-44-sample060.ogg.zip"),
		},
		TestAssetDef {
			filename : format!("bug-46-sample001.ogg"),
			hash : format!("d5015f9a3b79a28bf621ecc2e96286c20ef742e936e256f77b8978e6bce66aad"),
			url : format!("https://github.com/RustAudio/lewton/files/2923287/bug-46-sample001.ogg.zip"),
		},
	];
}


================================================
FILE: dev/cmp/src/main.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

extern crate lewton;
extern crate vorbis;
extern crate test_assets;

use std::env;

mod lib;
use lib::*;

fn main() {
	let command_name = env::args().nth(1).expect("No command found.");
	match command_name.as_ref() {
		"vals" =>  run_vals(), // Comparison of the output
		"perf" =>  run_perf(), // Comparison of speed
		"bench" =>  run_bench(), // Comparison of the output
		_ => println!("Error: invalid command.\n\
		Usage: <Command> <Filename>. Valid commands are \
		'vals' for output comparison, 'perf' for speed comparison, \
		and 'bench' for benchmarking a test file suite."),
	}
}

fn run_perf() {
	let file_path = env::args().nth(2).expect("Please specify a file to open via arg.");
	println!("Opening file: {}", file_path);
	let (decode_duration, native_decode_duration, n) = cmp_perf(&file_path);

	println!("Time to decode {} packets with libvorbis: {} s",
		n, native_decode_duration.as_secs_f64());
	println!("Time to decode {} packets with lewton: {} s",
		n, decode_duration.as_secs_f64());
	println!("Ratio of difference: {:.2}x",
		decode_duration.as_secs_f64() /
		native_decode_duration.as_secs_f64());
}

fn run_vals() {
	let file_path = env::args().nth(2).expect("Please specify a file to open via arg.");
	println!("Opening file: {}", file_path);
	let (pcks_with_diffs, n) = cmp_file_output(&file_path);
	if pcks_with_diffs > 0 {
		println!("Total number of packets with differences: {} of {} ({}%)",
			pcks_with_diffs, n, pcks_with_diffs as f32 / n as f32 * 100.0);
	} else {
		println!("No differences found.");
	}
}

fn run_bench() {
	println!("");
	test_assets::download_test_files(&get_asset_defs(),
		"test-assets", true).unwrap();
	println!("");
	use std::time::Duration;
	let mut total_native_time = Duration::from_secs(0);
	let mut total_time = Duration::from_secs(0);
	macro_rules! cmp_perf {
		($str:expr, $fill:expr) => {
			print!("Comparing speed for {} ", $str);
			let (decode_duration, native_decode_duration, _) =
				cmp_perf(&format!("test-assets/{}", $str));
			let ratio = decode_duration.as_secs_f64() /
				native_decode_duration.as_secs_f64();
			println!("{}: libvorbis={:.04}s we={:.4}s difference={:.2}x",
				$fill,
				native_decode_duration.as_secs_f64(),
				decode_duration.as_secs_f64(),
				ratio);
			total_native_time += native_decode_duration;
			total_time += decode_duration;
		};
	}
	cmp_perf!("bwv_1043_vivace.ogg", "");
	cmp_perf!("bwv_543_fuge.ogg", "   ");
	cmp_perf!("maple_leaf_rag.ogg", " ");
	cmp_perf!("hoelle_rache.ogg", "   ");
	cmp_perf!("thingy-floor0.ogg", "  ");
	println!("");
	println!("Overall time spent for decoding by libvorbis: {:.04}s",
		total_native_time.as_secs_f64());
	println!("Overall time spent for decoding by us: {:.04}s",
		total_time.as_secs_f64());
	println!("Overall ratio of difference: {:.2}x",
		total_time.as_secs_f64() /
		total_native_time.as_secs_f64());
}


================================================
FILE: dev/cmp/tests/fuzzed.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2018 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

extern crate test_assets;
#[macro_use]
extern crate cmp;
extern crate lewton;

#[test]
fn test_malformed_fuzzed() {
	println!();
	test_assets::download_test_files(&cmp::get_fuzzed_asset_defs(),
		"test-assets", true).unwrap();
	println!();

	use lewton::VorbisError::*;
	use lewton::audio::AudioReadError::*;
	use lewton::header::HeaderReadError::*;

	ensure_malformed!("27_really_minimized_testcase_crcfix.ogg", BadAudio(AudioBadFormat));
	ensure_malformed!("32_minimized_crash_testcase.ogg", BadHeader(HeaderBadFormat));
	ensure_malformed!("35_where_did_my_memory_go_repacked.ogg", BadHeader(HeaderBadFormat));

	ensure_malformed!("bug-42-sample009.ogg", BadAudio(AudioBadFormat));
	ensure_malformed!("bug-42-sample012.ogg", BadAudio(AudioBadFormat));
	//ensure_malformed!("bug-42-sample015.ogg", BadAudio(AudioBadFormat));

	ensure_malformed!("bug-44-sample059.ogg", BadHeader(HeaderBadFormat));
	ensure_malformed!("bug-44-sample060.ogg", BadHeader(HeaderBadFormat));

	ensure_malformed!("bug-46-sample001.ogg", BadAudio(AudioBadFormat));
}

#[test]
fn test_okay_fuzzed() {
	println!();
	test_assets::download_test_files(&cmp::get_fuzzed_asset_defs(),
		"test-assets", true).unwrap();
	println!();

	ensure_okay!("33_minimized_panic_testcase.ogg");
	ensure_okay!("bug-42-sample016.ogg");
	ensure_okay!("bug-42-sample029.ogg");
}


================================================
FILE: dev/cmp/tests/vals.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

extern crate test_assets;
extern crate lewton;
#[macro_use]
extern crate cmp;

use lewton::VorbisError::*;
use lewton::header::HeaderReadError::*;
use lewton::audio::AudioReadError::*;

macro_rules! cmp_output {
	($str:expr, $max_diff:expr) => {
		print!("Comparing output for {} ", $str);
		let (diff_pck_count, _) = cmp::cmp_file_output(&format!("test-assets/{}", $str));
		println!(": {} differing packets of allowed {}.", diff_pck_count, $max_diff);
		assert!(diff_pck_count <= $max_diff);
	};
}

#[test]
fn test_vals() {
	println!();
	test_assets::download_test_files(&cmp::get_asset_defs(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("bwv_1043_vivace.ogg", 0);
	cmp_output!("bwv_543_fuge.ogg", 0);
	cmp_output!("maple_leaf_rag.ogg", 0);
	cmp_output!("hoelle_rache.ogg", 0);
	cmp_output!("thingy-floor0.ogg", 0);
	cmp_output!("audio_simple_err.ogg", 0);
}

#[test]
fn test_libnogg_vals() {
	println!();
	test_assets::download_test_files(&cmp::get_libnogg_asset_defs(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("6-mode-bits-multipage.ogg", 2);
	cmp_output!("6-mode-bits.ogg", 2);
	cmp_output!("6ch-all-page-types.ogg", 0);
	cmp_output!("6ch-long-first-packet.ogg", 0);
	cmp_output!("6ch-moving-sine-floor0.ogg", 0);
	cmp_output!("6ch-moving-sine.ogg", 0);
	// NOTE: The bad-continued-packet-flag.ogg test is
	// actually supposed to return an error in libnogg.
	// However, libvorbis doesn't, nor does lewton.
	// Given a (slightly) erroneous ogg file where there
	// are audio packets following the last header packet,
	// we follow libvorbis behaviour and simply ignore those packets.
	// Apparently the test case has been created in a way
	// where this behaviour doesn't evoke an error from lewton.
	cmp_output!("bad-continued-packet-flag.ogg", 0);
	cmp_output!("bitrate-123.ogg", 0);
	cmp_output!("bitrate-456-0.ogg", 0);
	cmp_output!("bitrate-456-789.ogg", 0);
	cmp_output!("empty-page.ogg", 0);
	cmp_output!("large-pages.ogg", 2);
	cmp_output!("long-short.ogg", 2);
	cmp_output!("noise-6ch.ogg", 0);
	cmp_output!("noise-stereo.ogg", 0);
	cmp_output!("partial-granule-position.ogg", 2);
	#[cfg(not(target_os = "windows"))]
	cmp_output!("sample-rate-max.ogg", 0);
	ensure_malformed!("single-code-2bits.ogg", BadHeader(HeaderBadFormat));
	// We can't cmp the output here because native
	// libvorbis doesn't accept the file as valid
	ensure_okay!("single-code-nonsparse.ogg");
	ensure_okay!("single-code-ordered.ogg");
	cmp_output!("single-code-sparse.ogg", 0);
	#[cfg(not(target_os = "macos"))]
	cmp_output!("sketch008-floor0.ogg", 0);
	cmp_output!("sketch008.ogg", 0);
	cmp_output!("sketch039.ogg", 0);
	cmp_output!("split-packet.ogg", 2);
	cmp_output!("square-interleaved.ogg", 0);
	cmp_output!("square-multipage.ogg", 0);
	cmp_output!("square-stereo.ogg", 0);
	// This is really more an issue of the ogg crate,
	// if it's an issue at all.
	// https://github.com/RustAudio/ogg/issues/7
	//ensure_malformed!("square-with-junk.ogg", OggError(NoCapturePatternFound));
	cmp_output!("square.ogg", 0);
	cmp_output!("thingy.ogg", 0);
	cmp_output!("zero-length.ogg", 0);
}

#[test]
fn test_xiph_vals_1() {
	println!();
	test_assets::download_test_files(&cmp::get_xiph_asset_defs_1(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("1.0-test.ogg", 0);
	cmp_output!("1.0.1-test.ogg", 0);
	cmp_output!("48k-mono.ogg", 0);
	cmp_output!("beta3-test.ogg", 0);
	cmp_output!("beta4-test.ogg", 1);
}

#[test]
fn test_xiph_vals_2() {
	println!();
	test_assets::download_test_files(&cmp::get_xiph_asset_defs_2(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("bimS-silence.ogg", 0);
	cmp_output!("chain-test1.ogg", 0);
	cmp_output!("chain-test2.ogg", 0);
	cmp_output!("chain-test3.ogg", 1);
	cmp_output!("highrate-test.ogg", 0);
}

#[test]
fn test_xiph_vals_3() {
	println!();
	test_assets::download_test_files(&cmp::get_xiph_asset_defs_3(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("lsp-test.ogg", 0);
	cmp_output!("lsp-test2.ogg", 0);
	cmp_output!("lsp-test3.ogg", 0);
	cmp_output!("lsp-test4.ogg", 0);
	cmp_output!("mono.ogg", 0);
}

#[test]
fn test_xiph_vals_4() {
	println!();
	test_assets::download_test_files(&cmp::get_xiph_asset_defs_4(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("moog.ogg", 0);
	cmp_output!("one-entry-codebook-test.ogg", 0);
	cmp_output!("out-of-spec-blocksize.ogg", 0);
	cmp_output!("rc1-test.ogg", 0);
	cmp_output!("rc2-test.ogg", 0);
	cmp_output!("rc2-test2.ogg", 0);
	cmp_output!("rc3-test.ogg", 0);
}

#[test]
fn test_xiph_vals_5() {
	println!();
	test_assets::download_test_files(&cmp::get_xiph_asset_defs_5(),
		"test-assets", true).unwrap();
	println!();

	cmp_output!("singlemap-test.ogg", 0);
	#[cfg(not(target_os = "macos"))]
	cmp_output!("sleepzor.ogg", 0);
	cmp_output!("test-short.ogg", 0);
	cmp_output!("test-short2.ogg", 0);
	// Contains an out of bounds mode index
	ensure_malformed!("unused-mode-test.ogg", BadAudio(AudioBadFormat));
}


================================================
FILE: examples/perf.rs
================================================
// Vorbis decoder written in Rust
//
// This example file is licensed
// under the CC-0 license:
// https://creativecommons.org/publicdomain/zero/1.0/

extern crate lewton;
extern crate byteorder;

fn main() {
	match run() {
		Ok(_) =>(),
		Err(err) => println!("Error: {}", err),
	}
}

use std::env;
use lewton::VorbisError;
use lewton::inside_ogg::OggStreamReader;
use std::fs::File;
use std::time::Instant;

pub fn run() -> Result<(), VorbisError> {
	let file_path = env::args().nth(1).expect("No arg found. Please specify a file to open.");
	println!("Opening file: {}", file_path);
	let f = File::open(file_path).expect("Can't open file");

	let mut srr = OggStreamReader::new(f)?;

	println!("Sample rate: {}", srr.ident_hdr.audio_sample_rate);

	// Now the fun starts..
	let mut n = 0;
	let mut len_play = 0.0;
	let start_decode_time = Instant::now();
	while let Some(pck) = srr.read_dec_packet()? {
		n += 1;
		// This is guaranteed by the docs
		assert_eq!(pck.len(), srr.ident_hdr.audio_channels as usize);
		len_play += pck[0].len() as f32 / srr.ident_hdr.audio_sample_rate as f32;
	}
	let decode_duration = Instant::now() - start_decode_time;
	println!("The piece is {} s long ({} packets).", len_play, n);
	println!("Decoded in {} s.", decode_duration.as_secs() as f64 + (decode_duration.subsec_nanos() as f64) / 1_000_000_000.0);

	Ok(())
}


================================================
FILE: examples/player.rs
================================================
// Vorbis decoder written in Rust
//
// This example file is licensed
// under the CC-0 license:
// https://creativecommons.org/publicdomain/zero/1.0/

extern crate alto;
extern crate lewton;
extern crate byteorder;

use std::env;
use lewton::VorbisError;
use lewton::inside_ogg::OggStreamReader;
use std::fs::File;
use std::thread::sleep;
use std::time::{Instant, Duration};
use alto::{Alto, Mono, Stereo, Source};

fn main() {
	match run() {
		Ok(_) =>(),
		Err(err) => println!("Error: {}", err),
	}
}

fn run() -> Result<(), VorbisError> {
	let file_path = env::args().nth(1).expect("No arg found. Please specify a file to open.");
	println!("Opening file: {}", file_path);
	let f = File::open(file_path).expect("Can't open file");

	// Prepare the reading
	let mut srr = OggStreamReader::new(f)?;

	// Prepare the playback.
	let al = Alto::load_default().expect("Could not load alto");
	let device = al.open(None).expect("Could not open device");
	let cxt = device.new_context(None).expect("Could not create context");
	let mut str_src = cxt.new_streaming_source()
		.expect("could not create streaming src");
	let sample_rate = srr.ident_hdr.audio_sample_rate as i32;

	if srr.ident_hdr.audio_channels > 2 {
		// the openal crate can't process these many channels directly
		println!("Stream error: {} channels are too many!", srr.ident_hdr.audio_channels);
	}

	println!("Sample rate: {}", srr.ident_hdr.audio_sample_rate);

	// Now the fun starts..
	let mut n = 0;
	let mut len_play = 0.0;
	let mut start_play_time = None;
	let start_decode_time = Instant::now();
	let sample_channels = srr.ident_hdr.audio_channels as f32 *
		srr.ident_hdr.audio_sample_rate as f32;
	while let Some(pck_samples) = srr.read_dec_packet_itl()? {
		println!("Decoded packet no {}, with {} samples.", n, pck_samples.len());
		n += 1;
		let buf = match srr.ident_hdr.audio_channels {
			1 => cxt.new_buffer::<Mono<i16>,_>(&pck_samples, sample_rate),
			2 => cxt.new_buffer::<Stereo<i16>,_>(&pck_samples, sample_rate),
			n => panic!("unsupported number of channels: {}", n),
		}.unwrap();

		str_src.queue_buffer(buf).unwrap();

		len_play += pck_samples.len() as f32 / sample_channels;
		// If we are faster than realtime, we can already start playing now.
		if n == 100 {
			let cur = Instant::now();
			if cur - start_decode_time < Duration::from_millis((len_play * 1000.0) as u64) {
				start_play_time = Some(cur);
				str_src.play();
			}
		}
	}
	let total_duration = Duration::from_millis((len_play * 1000.0) as u64);
	let sleep_duration = total_duration - match start_play_time {
			None => {
				str_src.play();
				Duration::from_millis(0)
			},
			Some(t) => Instant::now() - t,
		};
	println!("The piece is {} s long.", len_play);
	sleep(sleep_duration);

	Ok(())
}


================================================
FILE: src/audio.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

/*!
Audio packet decoding

This module decodes the audio packets given to it.
*/

use std::error;
use std::fmt;
use std::cmp::min;
use std::iter;
use tinyvec::TinyVec;
use crate::ilog;
use bitpacking::BitpackCursor;
use header::{Codebook, Floor, FloorTypeZero, FloorTypeOne,
	HuffmanVqReadErr, IdentHeader, Mapping, Residue, SetupHeader};
use samples::Samples;

#[derive(Debug, PartialEq, Eq)]
pub enum AudioReadError {
	EndOfPacket,
	AudioBadFormat,
	AudioIsHeader,
	/// If the needed memory isn't addressable by us
	///
	/// This error is returned if a calculation yielded a higher value for
	/// an internal buffer size that doesn't fit into the platform's address range.
	/// Note that if we "simply" encounter an allocation failure (OOM, etc),
	/// we do what libstd does in these cases: crash.
	///
	/// This error is not automatically an error of the format,
	/// but rather is due to insufficient decoder hardware.
	BufferNotAddressable,
}

// For the () error type returned by the bitpacking layer
// TODO that type choice was a bit unfortunate,
// perhaps one day fix this
impl From<()> for AudioReadError {
	fn from(_ :()) -> AudioReadError {
		AudioReadError::EndOfPacket
	}
}

impl error::Error for AudioReadError {}

impl fmt::Display for AudioReadError {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		let description = match self {
			AudioReadError::EndOfPacket => "End of packet reached.",
			AudioReadError::AudioBadFormat => "Invalid audio packet",
			AudioReadError::AudioIsHeader => "The vorbis version is not supported",
			AudioReadError::BufferNotAddressable => "Requested to create buffer of non-addressable size",
		};
		write!(fmt, "{}", description)
	}
}

enum DecodedFloor<'a> {
	TypeZero(Vec<f32>, u64, &'a FloorTypeZero),
	TypeOne(Vec<u32>, &'a FloorTypeOne),
	Unused,
}

impl <'a> DecodedFloor<'a> {
	fn is_unused(&self) -> bool {
		match self {
			&DecodedFloor::Unused => true,
			_ => false,
		}
	}
}

enum FloorSpecialCase {
	Unused,
	PacketUndecodable,
}

impl From<()> for FloorSpecialCase {
	fn from(_ :()) -> Self {
		// () always means end of packet condition in the places
		// the conversion is used.
		return FloorSpecialCase::Unused;
	}
}

impl From<HuffmanVqReadErr> for FloorSpecialCase {
	fn from(e :HuffmanVqReadErr) -> Self {
		use ::header::HuffmanVqReadErr::*;
		use self::FloorSpecialCase::*;
		match e {
			EndOfPacket => Unused,
			// Undecodable per spec, see paragraph about
			// VQ lookup type zero in section 3.3.
			NoVqLookupForCodebook => PacketUndecodable,
		}
	}
}

// Note that the output vector contains the cosine values of the coefficients,
// not the bare values like in the spec. This is in order to optimize.
fn floor_zero_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],
		fl :&FloorTypeZero) -> Result<(Vec<f32>, u64), FloorSpecialCase> {
	// TODO this needs to become 128 bits wide, not just 64,
	// as floor0_amplitude_bits can be up to 127.
	let amplitude = try!(rdr.read_dyn_u64(fl.floor0_amplitude_bits));
	if amplitude <= 0 {
		// This channel is unused in this frame,
		// its all zeros.
		return Err(FloorSpecialCase::Unused);
	}

	let booknumber = try!(rdr.read_dyn_u32(
		ilog(fl.floor0_number_of_books as u64)));
	match fl.floor0_book_list.get(booknumber as usize) {
		// Undecodable per spec
		None => try!(Err(FloorSpecialCase::PacketUndecodable)),
		Some(codebook_idx) => {
			let mut coefficients = Vec::with_capacity(fl.floor0_order as usize);
			let mut last = 0.0;
			let codebook = &codebooks[*codebook_idx as usize];
			loop {
				let mut last_new = last;
				let temp_vector = try!(rdr.read_huffman_vq(codebook));
				if temp_vector.len() + coefficients.len() < fl.floor0_order as usize {
					// Little optimisation: we don't have to care about the >= case here
					for &e in temp_vector {
						coefficients.push((last + e as f32).cos());
						last_new = e as f32;
					}
				} else {
					for &e in temp_vector {
						coefficients.push((last + e as f32).cos());
						last_new = e as f32;
						// This rule makes sure that coefficients doesn't get
						// larger than floor0_order and saves an allocation
						// in this case
						if coefficients.len() == fl.floor0_order as usize {
							return Ok((coefficients, amplitude));
						}
					}
				}
				last += last_new;
				if coefficients.len() >= fl.floor0_order as usize {
					return Ok((coefficients, amplitude));
				}
			}
		},
	}
	unreachable!();
}

fn floor_zero_compute_curve(cos_coefficients :&[f32], amplitude :u64,
		fl :&FloorTypeZero, blockflag :bool, n :u16) -> Vec<f32> {
	let cached_bark_cos_omega =
		&fl.cached_bark_cos_omega[blockflag as usize];
	let mut i = 0;
	let mut output = Vec::with_capacity(n as usize);
	let lfv_common_term = amplitude as f32 * fl.floor0_amplitude_offset as f32 /
		((1 << fl.floor0_amplitude_bits) - 1) as f32;
	while i < n as usize {
		let cos_omega = cached_bark_cos_omega[i];

		// Compute p and q
		let (p_upper_border, q_upper_border) =
		if fl.floor0_order & 1 == 1 {
			((fl.floor0_order as usize - 3) / 2,
				(fl.floor0_order as usize - 1) / 2)
		} else {
			let v = (fl.floor0_order as usize - 2) / 2;
			(v, v)
		};
		let (mut p, mut q) =
		if fl.floor0_order & 1 == 1 {
			(1.0 - cos_omega * cos_omega, 0.25)
		} else {
			((1.0 - cos_omega) / 2.0, (1.0 + cos_omega) / 2.0)
		};
		for j in 0 .. p_upper_border + 1 {
			let pm = cos_coefficients[2 * j + 1] - cos_omega;
			p *= 4.0 * pm * pm;
		}
		for j in 0 .. q_upper_border + 1 {
			let qm = cos_coefficients[2 * j] - cos_omega;
			q *= 4.0 * qm * qm;
		}

		// Compute linear_floor_value
		let linear_floor_value = (0.11512925 *
			(lfv_common_term / (p+q).sqrt() - fl.floor0_amplitude_offset as f32)
		).exp();

		// Write into output
		let mut iteration_condition = cos_omega;
		while cos_omega == iteration_condition {
			output.push(linear_floor_value);
			i += 1;
			iteration_condition = match cached_bark_cos_omega.get(i) {
				Some(v) => *v,
				None => break,
			};
		}
	}
	return output;
}

// Returns Err if the floor is "unused"
fn floor_one_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],
		fl :&FloorTypeOne) -> Result<Vec<u32>, FloorSpecialCase> {
	// TODO perhaps it means invalid audio packet if reading the nonzero
	// flag doesn't succeed bc end of packet. Perhaps it does not.
	if !try!(rdr.read_bit_flag()) {
		try!(Err(()));
	}
	let mut floor1_y = Vec::new();
	let v = &[256, 128, 86, 64];
	let range = v[(fl.floor1_multiplier - 1) as usize];
	let b = ::ilog(range - 1);
	floor1_y.push(try!(rdr.read_dyn_u8(b)) as u32);
	floor1_y.push(try!(rdr.read_dyn_u8(b)) as u32);

	for class in &fl.floor1_partition_class {
		let uclass = *class as usize;
		let cdim = fl.floor1_class_dimensions[uclass];
		let cbits = fl.floor1_class_subclasses[uclass];
		let csub = (1 << cbits) - 1;
		let mut cval = 0;
		if cbits > 0 {
			let cbook = fl.floor1_class_masterbooks[uclass] as usize;
			cval = try!(rdr.read_huffman(&codebooks[cbook].codebook_huffman_tree));
		}
		for _ in 0 .. cdim {
			let book = fl.floor1_subclass_books[uclass][(cval & csub) as usize];
			cval >>= cbits;
			if book >= 0 {
				let tree = &codebooks[book as usize].codebook_huffman_tree;
				floor1_y.push(try!(rdr.read_huffman(tree)));
			} else {
				floor1_y.push(0);
			}
		}
	}
	return Ok(floor1_y);
}

fn extr_neighbor<F>(v :&[u32], max_idx :usize,
		compare :F, relation :&str) -> (usize, u32)
		where F :Fn(u32, u32) -> std::cmp::Ordering {
	use std::cmp::Ordering;

	let bound = v[max_idx];
	let prefix = &v[..max_idx];
	let smaller = |a, b| compare(a, b) == Ordering::Less;

	// First find a first index that fulfills
	// the criterion of being "smaller" than bound
	let min_idx = prefix.iter()
		.position(|&val| smaller(val, bound))
		.unwrap_or_else(||
			panic!("No index y < {0} found where v[y] is {1} than v[{0}] = 0x{2:08x}!",
				max_idx, relation, bound));

	// Now search for "bigger" entries
	let (offset, max_neighbor) = prefix[min_idx..].iter().cloned()
		.enumerate()
		// According to documentation of Iterator::max_by,
		// "If several elements are equally maximum, the last element is returned".
		// Thus, in order to find the *first* maximum element,
		// we need to search from the end of `prefix`
		.rev()
		.filter(|&(_i, val)| smaller(val, bound))
		.max_by(|&(_, a), &(_, b)| compare(a, b))
		.unwrap_or((0, v[min_idx]));

	(min_idx + offset, max_neighbor)
}

fn low_neighbor(v :&[u32], x :usize) -> (usize, u32) {
	extr_neighbor(v, x, |a, b| a.cmp(&b), "smaller")
}


fn high_neighbor(v :&[u32], x :usize) -> (usize, u32) {
	extr_neighbor(v, x, |a, b| b.cmp(&a), "bigger")
}

#[test]
fn test_low_neighbor() {
	let v = [1, 4, 2, 3, 6, 5];
	// 0 will panic
	assert_eq!(low_neighbor(&v, 1), (0, 1));
	assert_eq!(low_neighbor(&v, 2), (0, 1));
	assert_eq!(low_neighbor(&v, 3), (2, 2));
	assert_eq!(low_neighbor(&v, 4), (1, 4));
	assert_eq!(low_neighbor(&v, 5), (1, 4));
}


#[test]
fn test_high_neighbor() {
	let v = [1, 4, 2, 3, 6, 5];
	// 0, 1 will panic
	assert_eq!(high_neighbor(&v, 2), (1, 4));
	assert_eq!(high_neighbor(&v, 3), (1, 4));
	// 4 will panic
	assert_eq!(high_neighbor(&v, 5), (4, 6));
}

#[test]
fn test_high_neighbor_ex() {
	// Data extracted from example file
	let v = [0, 128, 12, 46, 4, 8, 16, 23,
		33, 70, 2, 6, 10, 14, 19, 28, 39, 58, 90];

	// 0, 1 will panic
	assert_eq!(high_neighbor(&v, 2), (1, 128));
	assert_eq!(high_neighbor(&v, 3), (1, 128));
	assert_eq!(high_neighbor(&v, 4), (2, 12));
	assert_eq!(high_neighbor(&v, 5), (2, 12));
	assert_eq!(high_neighbor(&v, 6), (3, 46));
	assert_eq!(high_neighbor(&v, 7), (3, 46));
	assert_eq!(high_neighbor(&v, 8), (3, 46));
	assert_eq!(high_neighbor(&v, 9), (1, 128));
	assert_eq!(high_neighbor(&v, 10), (4, 4));
	assert_eq!(high_neighbor(&v, 11), (5, 8));
	assert_eq!(high_neighbor(&v, 12), (2, 12));
	assert_eq!(high_neighbor(&v, 13), (6, 16));
	assert_eq!(high_neighbor(&v, 14), (7, 23));
	assert_eq!(high_neighbor(&v, 15), (8, 33));
	assert_eq!(high_neighbor(&v, 16), (3, 46));
	assert_eq!(high_neighbor(&v, 17), (9, 70));
	assert_eq!(high_neighbor(&v, 18), (1, 128));
}

#[test]
#[should_panic]
fn test_high_neighbor_panic() {
	high_neighbor(&[1, 4, 3, 2, 6, 5], 4);
}

#[test]
#[should_panic]
fn test_low_neighbor_panic() {
	low_neighbor(&[2, 4, 3, 1, 6, 5], 3);
}

fn render_point(x0 :u32, y0 :u32, x1 :u32, y1 :u32, x :u32) -> u32 {
	// TODO find out whether the type choices in this method are okay
	// (esp. the i32 choice).
	let dy = y1 as i32 - y0 as i32;
	let adx = x1 - x0;
	let ady = dy.abs() as u32;
	let err = ady * (x - x0);
	let off = err / adx;
	if dy < 0 {
		return y0 - off;
	} else {
		return y0 + off;
	}
}

#[test]
fn test_render_point() {
	// Test data taken from real life ogg/vorbis file.
	assert_eq!(render_point(0, 28, 128, 67, 12), 31);
	assert_eq!(render_point(12, 38, 128, 67, 46), 46);
	assert_eq!(render_point(0, 28, 12, 38, 4), 31);
	assert_eq!(render_point(4, 33, 12, 38, 8), 35);
	assert_eq!(render_point(12, 38, 46, 31, 16), 38);
	assert_eq!(render_point(16, 30, 46, 31, 23), 30);
	assert_eq!(render_point(23, 40, 46, 31, 33), 37);
	assert_eq!(render_point(46, 31, 128, 67, 70), 41);
	assert_eq!(render_point(0, 28, 4, 33, 2), 30);
	assert_eq!(render_point(4, 33, 8, 43, 6), 38);
	assert_eq!(render_point(8, 43, 12, 38, 10), 41);
	assert_eq!(render_point(12, 38, 16, 30, 14), 34);
	assert_eq!(render_point(16, 30, 23, 40, 19), 34);
	assert_eq!(render_point(23, 40, 33, 26, 28), 33);
	assert_eq!(render_point(33, 26, 46, 31, 39), 28);
	assert_eq!(render_point(46, 31, 70, 20, 58), 26);
	assert_eq!(render_point(70, 20, 128, 67, 90), 36);
}

fn floor_one_curve_compute_amplitude(floor1_y :&[u32], fl :&FloorTypeOne) -> (Vec<u32>, Vec<bool>) {
	let v = &[256, 128, 86, 64];
	let range = v[(fl.floor1_multiplier - 1) as usize] as i32;
	let mut floor1_step2_flag = Vec::new();
	floor1_step2_flag.push(true);
	floor1_step2_flag.push(true);
	let mut floor1_final_y = Vec::new();
	floor1_final_y.push(floor1_y[0]);
	floor1_final_y.push(floor1_y[1]);

	for (i, el) in fl.floor1_x_list.iter().enumerate().skip(2) {
		let cur_low_neighbor = low_neighbor(&fl.floor1_x_list, i);
		let cur_high_neighbor = high_neighbor(&fl.floor1_x_list, i);
		let predicted = render_point(
			cur_low_neighbor.1, floor1_final_y[cur_low_neighbor.0],
			cur_high_neighbor.1, floor1_final_y[cur_high_neighbor.0], *el) as i32;
		let val = floor1_y[i] as i32;
		let highroom = range - predicted;
		let lowroom = predicted;
		let room = min(highroom, lowroom) * 2;
		if val > 0 {
			floor1_step2_flag[cur_low_neighbor.0] = true;
			floor1_step2_flag[cur_high_neighbor.0] = true;
			floor1_step2_flag.push(true);
			floor1_final_y.push(if val >= room {
				if highroom > lowroom {
					predicted + val - lowroom
				} else {
					predicted - val + highroom - 1
				}
			} else {
				predicted + (if val % 2 == 1 {
					- val - 1 } else { val } >> 1)
			} as u32);
		} else {
			floor1_final_y.push(predicted as u32);
			floor1_step2_flag.push(false);
		}
	}
	// Clamp all entries of floor1_final_y to range
	for el in &mut floor1_final_y {
		*el = min(range as u32 - 1, *el);
	}
	return (floor1_final_y, floor1_step2_flag);
}

static FLOOR1_INVERSE_DB_TABLE :&[f32] = &[
	1.0649863e-07, 1.1341951e-07, 1.2079015e-07, 1.2863978e-07,
	1.3699951e-07, 1.4590251e-07, 1.5538408e-07, 1.6548181e-07,
	1.7623575e-07, 1.8768855e-07, 1.9988561e-07, 2.1287530e-07,
	2.2670913e-07, 2.4144197e-07, 2.5713223e-07, 2.7384213e-07,
	2.9163793e-07, 3.1059021e-07, 3.3077411e-07, 3.5226968e-07,
	3.7516214e-07, 3.9954229e-07, 4.2550680e-07, 4.5315863e-07,
	4.8260743e-07, 5.1396998e-07, 5.4737065e-07, 5.8294187e-07,
	6.2082472e-07, 6.6116941e-07, 7.0413592e-07, 7.4989464e-07,
	7.9862701e-07, 8.5052630e-07, 9.0579828e-07, 9.6466216e-07,
	1.0273513e-06, 1.0941144e-06, 1.1652161e-06, 1.2409384e-06,
	1.3215816e-06, 1.4074654e-06, 1.4989305e-06, 1.5963394e-06,
	1.7000785e-06, 1.8105592e-06, 1.9282195e-06, 2.0535261e-06,
	2.1869758e-06, 2.3290978e-06, 2.4804557e-06, 2.6416497e-06,
	2.8133190e-06, 2.9961443e-06, 3.1908506e-06, 3.3982101e-06,
	3.6190449e-06, 3.8542308e-06, 4.1047004e-06, 4.3714470e-06,
	4.6555282e-06, 4.9580707e-06, 5.2802740e-06, 5.6234160e-06,
	5.9888572e-06, 6.3780469e-06, 6.7925283e-06, 7.2339451e-06,
	7.7040476e-06, 8.2047000e-06, 8.7378876e-06, 9.3057248e-06,
	9.9104632e-06, 1.0554501e-05, 1.1240392e-05, 1.1970856e-05,
	1.2748789e-05, 1.3577278e-05, 1.4459606e-05, 1.5399272e-05,
	1.6400004e-05, 1.7465768e-05, 1.8600792e-05, 1.9809576e-05,
	2.1096914e-05, 2.2467911e-05, 2.3928002e-05, 2.5482978e-05,
	2.7139006e-05, 2.8902651e-05, 3.0780908e-05, 3.2781225e-05,
	3.4911534e-05, 3.7180282e-05, 3.9596466e-05, 4.2169667e-05,
	4.4910090e-05, 4.7828601e-05, 5.0936773e-05, 5.4246931e-05,
	5.7772202e-05, 6.1526565e-05, 6.5524908e-05, 6.9783085e-05,
	7.4317983e-05, 7.9147585e-05, 8.4291040e-05, 8.9768747e-05,
	9.5602426e-05, 0.00010181521, 0.00010843174, 0.00011547824,
	0.00012298267, 0.00013097477, 0.00013948625, 0.00014855085,
	0.00015820453, 0.00016848555, 0.00017943469, 0.00019109536,
	0.00020351382, 0.00021673929, 0.00023082423, 0.00024582449,
	0.00026179955, 0.00027881276, 0.00029693158, 0.00031622787,
	0.00033677814, 0.00035866388, 0.00038197188, 0.00040679456,
	0.00043323036, 0.00046138411, 0.00049136745, 0.00052329927,
	0.00055730621, 0.00059352311, 0.00063209358, 0.00067317058,
	0.00071691700, 0.00076350630, 0.00081312324, 0.00086596457,
	0.00092223983, 0.00098217216, 0.0010459992,  0.0011139742,
	0.0011863665,  0.0012634633,  0.0013455702,  0.0014330129,
	0.0015261382,  0.0016253153,  0.0017309374,  0.0018434235,
	0.0019632195,  0.0020908006,  0.0022266726,  0.0023713743,
	0.0025254795,  0.0026895994,  0.0028643847,  0.0030505286,
	0.0032487691,  0.0034598925,  0.0036847358,  0.0039241906,
	0.0041792066,  0.0044507950,  0.0047400328,  0.0050480668,
	0.0053761186,  0.0057254891,  0.0060975636,  0.0064938176,
	0.0069158225,  0.0073652516,  0.0078438871,  0.0083536271,
	0.0088964928,  0.009474637,   0.010090352,   0.010746080,
	0.011444421,   0.012188144,   0.012980198,   0.013823725,
	0.014722068,   0.015678791,   0.016697687,   0.017782797,
	0.018938423,   0.020169149,   0.021479854,   0.022875735,
	0.024362330,   0.025945531,   0.027631618,   0.029427276,
	0.031339626,   0.033376252,   0.035545228,   0.037855157,
	0.040315199,   0.042935108,   0.045725273,   0.048696758,
	0.051861348,   0.055231591,   0.058820850,   0.062643361,
	0.066714279,   0.071049749,   0.075666962,   0.080584227,
	0.085821044,   0.091398179,   0.097337747,   0.10366330,
	0.11039993,    0.11757434,    0.12521498,    0.13335215,
	0.14201813,    0.15124727,    0.16107617,    0.17154380,
	0.18269168,    0.19456402,    0.20720788,    0.22067342,
	0.23501402,    0.25028656,    0.26655159,    0.28387361,
	0.30232132,    0.32196786,    0.34289114,    0.36517414,
	0.38890521,    0.41417847,    0.44109412,    0.46975890,
	0.50028648,    0.53279791,    0.56742212,    0.60429640,
	0.64356699,    0.68538959,    0.72993007,    0.77736504,
	0.82788260,    0.88168307,    0.9389798,     1.];

fn render_line(x0 :u32, y0 :u32, x1 :u32, y1 :u32, v :&mut Vec<u32>) {
	// TODO find out whether the type choices in this method are okay
	let dy = y1 as i32 - y0 as i32;
	let adx = x1 as i32 - x0 as i32;
	let ady = dy.abs();
	let base = dy / adx;
	let mut y = y0 as i32;
	let mut err = 0;
	let sy = base + (if dy < 0 { -1 } else { 1 });
	let ady = ady  - base.abs() * adx;
	v.push(y as u32);
	for _ in (x0 + 1) .. x1 {
		err += ady;
		if err >= adx {
			err -= adx;
			y += sy;
		} else {
			y += base;
		}
		v.push(y as u32);
	}
}

fn floor_one_curve_synthesis(floor1_final_y :Vec<u32>,
		floor1_step2_flag :Vec<bool>, fl :&FloorTypeOne, n :u16) -> Vec<f32> {
	let floor1_final_y_s = |i :usize| { floor1_final_y[fl.floor1_x_list_sorted[i].0] };
	let floor1_x_list_s = |i :usize| { fl.floor1_x_list_sorted[i].1 };
	let floor1_step2_flag_s = |i :usize| {
		floor1_step2_flag[fl.floor1_x_list_sorted[i].0] };
	let mut hx = 0;
	let mut lx = 0;
	let mut hy = 0;
	let mut floor = Vec::with_capacity(n as usize);
	let mut ly = floor1_final_y_s(0) * fl.floor1_multiplier as u32;
	for i in 1 .. fl.floor1_x_list.len() {
		if floor1_step2_flag_s(i) {
			hy = floor1_final_y_s(i) * fl.floor1_multiplier as u32;
			hx = floor1_x_list_s(i);
			render_line(lx, ly, hx, hy, &mut floor);
			lx = hx;
			ly = hy;
		}
	}
	if hx < n as u32 {
		render_line(hx, hy, n as u32, hy, &mut floor);
	} else if hx > n as u32 {
		floor.truncate(n as usize);
	}

	floor.into_iter()
		.map(|idx| FLOOR1_INVERSE_DB_TABLE[idx as usize])
		.collect()
}

fn floor_decode<'a>(rdr :&mut BitpackCursor,
		ident :&IdentHeader, mapping :&Mapping, codebooks :&[Codebook],
		floors :&'a [Floor]) -> Result<Vec<DecodedFloor<'a>>, ()> {
	let mut decoded_floor_infos = Vec::with_capacity(ident.audio_channels as usize);
	for i in 0 .. ident.audio_channels as usize {
		let submap_number = mapping.mapping_mux[i] as usize;
		let floor_number = mapping.mapping_submap_floors[submap_number];
		let floor = &floors[floor_number as usize];
		use self::FloorSpecialCase::*;
		let floor_res = match floor {
			&Floor::TypeZero(ref fl) => {
				match floor_zero_decode(rdr, codebooks, fl) {
					Ok((coeff, amp)) => DecodedFloor::TypeZero(coeff, amp, fl),
					Err(Unused) => DecodedFloor::Unused,
					Err(PacketUndecodable) => try!(Err(())),
				}
			},
			&Floor::TypeOne(ref fl) => {
				match floor_one_decode(rdr, codebooks, fl) {
					Ok(dfl) => DecodedFloor::TypeOne(dfl, fl),
					Err(Unused) => DecodedFloor::Unused,
					Err(PacketUndecodable) => try!(Err(())),
				}
			},
		};
		decoded_floor_infos.push(floor_res);
	}
	return Ok(decoded_floor_infos);
}

fn residue_packet_read_partition(rdr :&mut BitpackCursor, codebook :&Codebook,
		resid :&Residue, vec_v :&mut [f32]) -> Result<(), HuffmanVqReadErr> {
	if resid.residue_type == 0 {
		let codebook_dimensions = codebook.codebook_dimensions as usize;
		let step = resid.residue_partition_size as usize / codebook_dimensions;
		for i in 0 .. step {
			let entry_temp = try!(rdr.read_huffman_vq(codebook));
			for (j, e) in entry_temp.iter().enumerate() {
				vec_v[i + j * step] += *e;
			}
		}
	} else {
		// Common for both format 1 and 2
		let partition_size = resid.residue_partition_size as usize;
		let mut i = 0;
		while i < partition_size {
			let entries = try!(rdr.read_huffman_vq(codebook));
			let vs = if let Some(vs) = vec_v.get_mut(i..(i + entries.len())) {
				vs
			} else {
				break;
			};

			for (v, e) in vs.iter_mut().zip(entries.iter()) {
				*v += *e;
			}

			i += entries.len();
		}
	}
	Ok(())
}

fn residue_packet_decode_inner(rdr :&mut BitpackCursor, cur_blocksize :u16,
		do_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result<Vec<f32>, ()> {

	let ch = do_not_decode_flag.len();
	let actual_size = (cur_blocksize / 2) as usize;

	// Older versions of the spec say max() here,
	// but there's been a bug in the spec.
	// It's been fixed since:
	// https://github.com/xiph/vorbis/pull/35
	let limit_residue_begin = min(resid.residue_begin as usize, actual_size);
	let limit_residue_end = min(resid.residue_end as usize, actual_size);

	let cur_codebook = &codebooks[resid.residue_classbook as usize];
	let classwords_per_codeword = cur_codebook.codebook_dimensions as usize;
	let n_to_read = limit_residue_end - limit_residue_begin;
	let partitions_to_read = n_to_read / resid.residue_partition_size as usize;
	let residue_classbok_ht = &cur_codebook.codebook_huffman_tree;

	// Allocate and zero all vectors that will be returned
	let mut vectors = vec![0.; ch * actual_size];

	if n_to_read == 0 {
		// No residue to decode
		return Ok(vectors);
	}

	if classwords_per_codeword == 0 {
		// A value of 0 would create an infinite loop.
		// Therefore, throw an error in this case.
		try!(Err(()));
	}

	'pseudo_return: loop {
		// ENdofpacketisnOrmal macro. Local replacement for try.
		macro_rules! eno {
			($expr:expr) => (match $expr {
				$crate::std::result::Result::Ok(val) => val,
				$crate::std::result::Result::Err(_) => break 'pseudo_return,
			})
		}
		let cl_stride :usize = partitions_to_read + classwords_per_codeword;
		let mut classifications = vec![0; ch as usize * cl_stride];
		for pass in 0 .. 8 {
			let mut partition_count = 0;
			while partition_count < partitions_to_read {
				if pass == 0 {
					for (j, do_not_decode) in do_not_decode_flag.iter().enumerate() {
						if *do_not_decode {
							continue;
						}
						let mut temp = eno!(rdr.read_huffman(residue_classbok_ht));
						for i in (0 .. classwords_per_codeword).rev() {
							classifications[j * cl_stride + i + partition_count] =
							temp % resid.residue_classifications as u32;
							temp = temp / resid.residue_classifications as u32;
						}
					}
				}
				for _ in 0 .. classwords_per_codeword {
					if partition_count >= partitions_to_read {
						break;
					}
					for (j, do_not_decode) in do_not_decode_flag.iter().enumerate() {
						if *do_not_decode {
							continue;
						}
						let offs = limit_residue_begin + partition_count * resid.residue_partition_size as usize;
						let vec_j_offs = &mut vectors[(j * actual_size + offs) .. ((j + 1) * actual_size)];
						let vqclass = classifications[j * cl_stride + partition_count] as usize;
						let vqbook_opt = resid.residue_books[vqclass].get_val(pass);
						if let Some(vqbook) = vqbook_opt {
							let codebook = &codebooks[vqbook as usize];
							// codebook is checked by header decode to have a value mapping
							// Decode the partition into output vector number j (vec_j).
							match residue_packet_read_partition(rdr,
									codebook, resid, vec_j_offs) {
								Ok(_) => (),
								Err(err) => {
									use ::header::HuffmanVqReadErr::*;
									match err {
										EndOfPacket => break 'pseudo_return,
										NoVqLookupForCodebook =>
											panic!("Codebook must have a value mapping"),
									}
								},
							}
						}
					}
					partition_count += 1;
				}
			}
		}
		break;
	}

	return Ok(vectors);
}


// Ok means "fine" (or end of packet, but thats "fine" too!),
// Err means "not fine" -- the whole packet must be discarded
fn residue_packet_decode(rdr :&mut BitpackCursor, cur_blocksize :u16,
		do_not_decode_flag :&[bool], resid :&Residue, codebooks :&[Codebook]) -> Result<Vec<f32>, ()> {

	let ch = do_not_decode_flag.len();
	let vec_size = (cur_blocksize / 2) as usize;

	if resid.residue_type == 2 {
		let mut to_decode_found = false;
		for do_not_decode in do_not_decode_flag {
			if !do_not_decode {
				to_decode_found = true;
				break;
			}
		}
		if !to_decode_found {
			// Don't attempt to decode, but return vectors,
			// as required per spec only residue 2 has this.
			return Ok(vec![0.; ch * vec_size]);
		} else {
			// Construct a do_not_decode flag array
			let c_do_not_decode_flag = [false];

			let vectors = try!(residue_packet_decode_inner(rdr,
				cur_blocksize * ch as u16, &c_do_not_decode_flag,
				resid, codebooks));

			// Post decode step
			let mut vectors_deinterleaved = Vec::with_capacity(ch * vec_size);
			for j in 0 .. ch {
				let iter = vectors.chunks(ch).map(|chunk| chunk[j]);
				vectors_deinterleaved.extend(iter);
			}
			return Ok(vectors_deinterleaved);
		}
	} else {
		return residue_packet_decode_inner(rdr, cur_blocksize,
			do_not_decode_flag, resid, codebooks);
	}
}

#[inline]
fn inverse_couple(m :f32, a :f32) -> (f32, f32) {
	if m > 0. {
		if a > 0. {
			(m, m - a)
		} else {
			(m + a, m)
		}
	} else {
		if a > 0. {
			(m, m + a)
		} else {
			(m - a, m)
		}
	}
}

// TODO this is probably slower than a replacement of
// this function in unsafe code, no idea
fn dual_mut_idx<T>(v :&mut [T], idx_a :usize, idx_b :usize)
		-> (&mut T, &mut T) {
	assert_ne!(idx_a, idx_b, "not allowed, indices must be different!");

	let range = if idx_a < idx_b { idx_a..idx_b+1 } else { idx_b..idx_a+1 };
	let segment = &mut v[range];
	let (first, rest) = segment.split_first_mut().unwrap();
	let (last, _) = rest.split_last_mut().unwrap();
	(first, last)
}

fn dct_iv_slow(buffer :&mut [f32]) {
	let x = buffer.to_vec();
	let n = buffer.len();
	let nmask = (n << 3) - 1;
	let mcos = (0 .. 8 * n)
		.map(|i| (std::f32::consts::FRAC_PI_4 * (i as f32) / (n as f32)).cos())
		.collect::<Vec<_>>();
	for i in 0 .. n {
		let mut acc = 0.;
		for j in 0 .. n {
			acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask];
		}
		buffer[i] = acc;
	}
}

#[allow(dead_code)]
fn inverse_mdct_slow(buffer :&mut [f32]) {
	let n = buffer.len();
	let n4 = n >> 2;
	let n2 = n >> 1;
	let n3_4 = n - n4;
	let mut temp = buffer[0 .. n2].to_vec();
	dct_iv_slow(&mut temp); // returns -c'-d, a-b'
	for i in 0 .. n4 {
		buffer[i] = temp[i + n4]; // a-b'
	}
	for i in n4 .. n3_4 {
		buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d'
	}
	for i in n3_4 .. n {
		buffer[i] = -temp[i - n3_4]; // c'+d
	}
}

#[cfg(test)]
#[test]
fn test_imdct_slow() {
	use imdct_test::*;
	let mut arr_1 = imdct_prepare(&IMDCT_INPUT_TEST_ARR_1);
	inverse_mdct_slow(&mut arr_1);
	let mismatches = fuzzy_compare_array(
		&arr_1, &IMDCT_OUTPUT_TEST_ARR_1,
		0.00005, true);
	let mismatches_limit = 0;
	if mismatches > mismatches_limit {
		panic!("Numer of mismatches {} was larger than limit of {}",
			mismatches, mismatches_limit);
	}
}

/// The right part of the previous window
///
/// This is the only state that needs to be changed
/// once the headers are read.
#[derive(Clone)]
pub struct PreviousWindowRight {
	data :Option<Vec<Vec<f32>>>,
}

impl PreviousWindowRight {
	/// Initialisation for new streams
	pub fn new() -> Self {
		return PreviousWindowRight{ data : None };
	}
	/// If the state is still uninitialized
	pub fn is_empty(&self) -> bool {
		self.data.is_none()
	}
}

/**
Returns the per-channel sample count of a packet if it were decoded.

This operation is very cheap and doesn't involve actual decoding of the packet.

Note: for the first packet in a stream, or in other instances when
the `PreviousWindowRight` is reset, the decoding functions will return
0 samples for that packet, while this function returns a different number.
Please use the `PreviousWindowRight::is_empty` function or other methods
to check for this case.
*/
pub fn get_decoded_sample_count(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8])
		-> Result<usize, AudioReadError> {
	let mut rdr = BitpackCursor::new(packet);
	if try!(rdr.read_bit_flag()) {
		try!(Err(AudioReadError::AudioIsHeader));
	}
	let mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1)));
	let mode = &setup.modes[mode_number as usize];
	let bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 };
	let n :u16 = 1 << bs;
	let previous_next_window_flag = if mode.mode_blockflag {
		Some((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag())))
	} else {
		None
	};
	// Compute windowing info for left window
	let window_center = n >> 1;
	let (left_win_start, _left_win_end, _left_n, _left_n_use_bs1) =
		if previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) {
			(0, window_center, n >> 1, mode.mode_blockflag)
		} else {
			let bs_0_exp = 1 << ident.blocksize_0;
			((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false)
		};

	// Compute windowing info for right window
	let (right_win_start, _right_win_end) =
		if previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) {
			(window_center, n)
		} else {
			let bs_0_exp = 1 << ident.blocksize_0;
			((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2)
		};

	Ok((right_win_start - left_win_start) as usize)
}

/**
Main audio packet decoding function

Pass your info to this function to get your raw packet data decoded.

Panics if the passed PreviousWindowRight struct doesn't match the info
from the ident header.
*/
pub fn read_audio_packet_generic<S :Samples>(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight)
		-> Result<S, AudioReadError> {
	let mut rdr = BitpackCursor::new(packet);
	if try!(rdr.read_bit_flag()) {
		try!(Err(AudioReadError::AudioIsHeader));
	}
	let mode_number = try!(rdr.read_dyn_u8(ilog(setup.modes.len() as u64 - 1)));
	let mode = if let Some(mode) = setup.modes.get(mode_number as usize) {
		mode
	} else {
		try!(Err(AudioReadError::AudioBadFormat))
	};
	let mapping = &setup.mappings[mode.mode_mapping as usize];
	let bs = if mode.mode_blockflag { ident.blocksize_1 } else { ident.blocksize_0 };
	let n :u16 = 1 << bs;
	let previous_next_window_flag = if mode.mode_blockflag {
		Some((try!(rdr.read_bit_flag()), try!(rdr.read_bit_flag())))
	} else {
		None
	};
	// Decode the floors
	let decoded_floor_infos = try!(floor_decode(&mut rdr, ident, mapping,
		&setup.codebooks, &setup.floors));

	// Now calculate the no_residue vector
	let mut no_residue = TinyVec::<[bool; 32]>::new();
	for fl in &decoded_floor_infos {
		no_residue.push(fl.is_unused());
	}
	// and also propagate
	for (&mag, &angle) in
			mapping.mapping_magnitudes.iter().zip(mapping.mapping_angles.iter()) {
		if ! (no_residue[mag as usize] && no_residue[angle as usize]) {
			no_residue[mag as usize] = false;
			no_residue[angle as usize] = false;
		}
	}

	// Residue decode.
	let mut residue_vectors = vec![vec![]; mapping.mapping_mux.len()];
	// Helper variable
	let resid_vec_len = (n / 2) as usize;
	for (i, &residue_number) in mapping.mapping_submap_residues.iter().enumerate() {
		let mut do_not_decode_flag = TinyVec::<[bool; 32]>::new();
		for (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() {
			if mapping_mux_j as usize == i {
				do_not_decode_flag.push(no_residue[j]);
			}
		}
		let cur_residue = &setup.residues[residue_number as usize];
		let vectors = match residue_packet_decode(&mut rdr, n,
				&do_not_decode_flag, cur_residue, &setup.codebooks) {
			Ok(v) => v,
			Err(_) => return Err(AudioReadError::AudioBadFormat),
		};
		// The vectors Vec<f32> now contains the do_not_decode_flag.len()
		// many decoded residue vectors, each vector occupying n/2 scalars.
		let mut ch = 0;
		for (j, &mapping_mux_j) in mapping.mapping_mux.iter().enumerate() {
			if mapping_mux_j as usize == i {
				// TODO get rid of this copy somehow...
				let vec_at_ch = &vectors[resid_vec_len * ch .. resid_vec_len * (ch + 1)];
				residue_vectors[j].clear();
				residue_vectors[j].extend_from_slice(vec_at_ch);
				ch += 1;
			}
		}
	}

	record_residue_pre_inverse!(residue_vectors);

	// Inverse coupling
	for (&mag, &angle) in
			mapping.mapping_magnitudes.iter().rev().zip(mapping.mapping_angles.iter().rev()) {
		let (mag_vector, angle_vector) = dual_mut_idx(&mut residue_vectors,
			mag as usize, angle as usize);
		for (m, a) in mag_vector.iter_mut().zip(angle_vector.iter_mut()) {
			// https://github.com/rust-lang/rfcs/issues/372
			// grumble grumble...
			let (new_m, new_a) = inverse_couple(*m, *a);
			*m = new_m;
			*a = new_a;
		}
	}

	record_residue_post_inverse!(residue_vectors);

	// Dot product
	let mut audio_spectri = Vec::with_capacity(ident.audio_channels as usize);
	for (residue_vector, chan_decoded_floor) in
			residue_vectors.iter().zip(decoded_floor_infos.iter()) {
		let mut floor_decoded :Vec<f32> = match chan_decoded_floor {
			&DecodedFloor::TypeZero(ref coefficients, amplitude, ref fl) => {
				floor_zero_compute_curve(coefficients, amplitude,
					fl, mode.mode_blockflag, n / 2)
			},
			&DecodedFloor::TypeOne(ref floor_y, ref fl) => {
				let (floor1_final_y, floor1_step2_flag) =
					floor_one_curve_compute_amplitude(floor_y, fl);
				floor_one_curve_synthesis(floor1_final_y,
					floor1_step2_flag, fl, n / 2)
			},
			&DecodedFloor::Unused => {
				// Generate zero'd floor of length n/2
				vec![0.; (n / 2) as usize]
			},
		};

		// The only legal length is n/2.
		// The implementation should ensure this,
		// but its good for debugging to have this
		// confirmed.
		debug_assert_eq!(residue_vector.len(), (n / 2) as usize);
		debug_assert_eq!(floor_decoded.len(), (n / 2) as usize);

		// Now do the multiplication
		for (fl_sc, r_sc) in floor_decoded.iter_mut().zip(residue_vector.iter()) {
			*fl_sc *= *r_sc;
		}
		audio_spectri.push(floor_decoded);
	}

	record_pre_mdct!(audio_spectri);

	// Inverse MDCT
	for ref mut spectrum in audio_spectri.iter_mut() {
		let size = (n / 2) as usize;
		let ext = iter::repeat(0.).take(size);
		spectrum.extend(ext);
		let cached_bd = &ident.cached_bs_derived[mode.mode_blockflag as usize];
		//::imdct::inverse_mdct_naive(cached_bd, &mut spectrum[..]);
		::imdct::inverse_mdct(cached_bd, &mut spectrum[..], bs);
		//inverse_mdct_slow(&mut spectrum[..]);
	}

	record_post_mdct!(audio_spectri);

	// Compute windowing info for left window
	let window_center = n >> 1;
	let (left_win_start, _left_win_end, _left_n, left_n_use_bs1) =
		if previous_next_window_flag.map_or(true, |(prev_win_flag, _)| prev_win_flag) {
			(0, window_center, n >> 1, mode.mode_blockflag)
		} else {
			let bs_0_exp = 1 << ident.blocksize_0;
			((n - bs_0_exp) >> 2, (n + bs_0_exp) >> 2, bs_0_exp >> 1, false)
		};

	// Compute windowing info for right window
	let (right_win_start, right_win_end) =
		if previous_next_window_flag.map_or(true, |(_, next_win_flag)| next_win_flag) {
			(window_center, n)
		} else {
			let bs_0_exp = 1 << ident.blocksize_0;
			((n * 3 - bs_0_exp) >> 2, (n * 3 + bs_0_exp) >> 2)
		};

	/*println!("n={} prev_win_flag={:?} left_win_(start={}, end={}, n={}) right_win(start={}, end={})",
		n, previous_next_window_flag, left_win_start, _left_win_end, _left_n,
		right_win_start, right_win_end); // */

	// Overlap add and store last half
	// in PreviousWindowRight
	// Only add if prev has elements.
	let mut future_prev_halves = Vec::with_capacity(ident.audio_channels as usize);
	if let Some(prev_data) = pwr.data.take() {
		// TODO maybe check if prev_n matches blocksize_0 or blocksize_1,
		// and the channel number. Panic if no match of either.
		assert_eq!(audio_spectri.len(), prev_data.len());

		let win_slope = &ident.cached_bs_derived[left_n_use_bs1 as usize].window_slope;

		for (prev_chan, chan) in prev_data.into_iter().zip(audio_spectri.iter_mut()) {
			let plen = prev_chan.len();
			let left_win_start = left_win_start as usize;
			let right_win_start = right_win_start as usize;
			let right_win_end = right_win_end as usize;

			// Then do the actual overlap_add
			// Set up iterators for all the variables
			let range = {
				let start = left_win_start;
				let end = left_win_start + plen;
				start..end
			};

			let prev = prev_chan.iter();

			let (lhs, rhs) = {
				if win_slope.len() < plen {
					// According to fuzzing, code can trigger this case,
					// so let's error gracefully instead of panicing.
					try!(Err(AudioReadError::AudioBadFormat));
				}
				let win_slope = &win_slope[0..plen];
				(win_slope.iter(), win_slope.iter().rev())
			};

			for (((v, lhs), prev), rhs) in chan[range].iter_mut().zip(lhs).zip(prev).zip(rhs) {
				*v = (*v * lhs) + (prev * rhs);
			}

  			// and populate the future previous half
			let future_prev_half = chan[right_win_start..right_win_end].into();

			future_prev_halves.push(future_prev_half);

			// Remove everything left of the left window start,
			// by moving the the stuff right to it to the left.
			if left_win_start > 0 {
				for i in 0 .. right_win_start - left_win_start {
					chan[i] = chan[i + left_win_start];
				}
			}

			// Now the last step: truncate the decoded packet
			// to cut off the right part.
			chan.truncate(right_win_start - left_win_start);
			// TODO stb_vorbis doesn't use right_win_start
			// in the calculation above but sth like
			// if len < right_win_start { len } else { right_win_start }
		}
	} else {
		for chan in audio_spectri.iter_mut() {
			let mut future_prev_half = Vec::with_capacity(
				(right_win_end - right_win_start) as usize);
			for s in &chan[right_win_start as usize .. right_win_end as usize] {
				future_prev_half.push(*s);
			}
			future_prev_halves.push(future_prev_half);
			// If there is no previous window right, we have to discard
			// the whole packet.
			chan.truncate(0);
		}
	}

	pwr.data = Some(future_prev_halves);

	// Generate final integer samples
	let final_i16_samples = S::from_floats(audio_spectri);

	Ok(final_i16_samples)
}

/**
Main audio packet decoding function

Pass your info to this function to get your raw packet data decoded.

Panics if the passed PreviousWindowRight struct doesn't match the info
from the ident header.
*/
pub fn read_audio_packet(ident :&IdentHeader, setup :&SetupHeader, packet :&[u8], pwr :&mut PreviousWindowRight)
		-> Result<Vec<Vec<i16>>, AudioReadError> {
	read_audio_packet_generic(ident, setup, packet, pwr)
}


================================================
FILE: src/bitpacking.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

/*!
Vorbis bitpacking layer

Functionality to read content from the bitpacking layer.

Implements vorbis spec, section 2.

The most important struct of this mod is the `BitpackCursor` struct.
It can be instantiated using `BitpackCursor::new()`.

Note that this implementation doesn't fully align with the spec in the regard that it assumes a byte is an octet.
This is no problem on most architectures.
This non-alignment to the spec is due to the fact that the rust language is highly leaned towards byte == u8,
and doesn't even have a builtin single byte type.
*/

use huffman_tree::{VorbisHuffmanTree, PeekedDataLookupResult};

/// A Cursor on slices to read numbers and bitflags, bit aligned.
pub struct BitpackCursor <'a> {
	bit_cursor :u8,
	byte_cursor :usize,
	inner :&'a[u8],
}

macro_rules! sign_extend {
	($num:expr, $desttype:ident, $bit_cnt_large:expr, $bit_cnt_small:expr) => {{
		let n = $num;
		let res :$desttype = n as $desttype;
		let k :u8 = $bit_cnt_large - $bit_cnt_small;
		res << k >> k
	}};
}

#[test]
fn test_sign_extend() {
	assert_eq!(sign_extend!(0b00,  i8,  8,  2),  0);
	assert_eq!(sign_extend!(0b01,  i8,  8,  2),  1);
	assert_eq!(sign_extend!(0b11,  i8,  8,  2), -1);
	assert_eq!(sign_extend!(0b111, i8,  8,  3), -1);
	assert_eq!(sign_extend!(0b101, i8,  8,  3), -3);
	assert_eq!(sign_extend!(0b01111110, i16, 16, 8),  126);
	assert_eq!(sign_extend!(0b10000010, i16, 16, 8), -126);
}

/// Returns `num` bits of 1 (but never more than 8).
fn mask_bits(num : u8) -> u8 {
	!((!0u8).wrapping_shl(num as u32)) | if num >= 8 { 0xff } else { 0 }
}

// Same as mask_bits but different in a special case: for num % 8 == 0
// Make sure that 0 <= num <= 8.
fn bmask_bits(num : u8) -> u8 {
	(!0u8).wrapping_shr(8 - num as u32)
}

#[test]
fn test_mask_bits() {
	assert_eq!(mask_bits(0), 0b00000000);
	assert_eq!(mask_bits(1), 0b00000001);
	assert_eq!(mask_bits(2), 0b00000011);
	assert_eq!(mask_bits(3), 0b00000111);
	assert_eq!(mask_bits(4), 0b00001111);
	assert_eq!(mask_bits(5), 0b00011111);
	assert_eq!(mask_bits(6), 0b00111111);
	assert_eq!(mask_bits(7), 0b01111111);
	assert_eq!(mask_bits(8), 0b11111111);
}

#[test]
fn test_bmask_bits() {
	assert_eq!(bmask_bits(0), 0b11111111);
	assert_eq!(bmask_bits(1), 0b00000001);
	assert_eq!(bmask_bits(2), 0b00000011);
	assert_eq!(bmask_bits(3), 0b00000111);
	assert_eq!(bmask_bits(4), 0b00001111);
	assert_eq!(bmask_bits(5), 0b00011111);
	assert_eq!(bmask_bits(6), 0b00111111);
	assert_eq!(bmask_bits(7), 0b01111111);
	assert_eq!(bmask_bits(8), 0b11111111);
}

// The main macro to read bit aligned
// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)
macro_rules! bpc_read_body {
	($rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr) => {{
		let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;
		let octetnum_rounded_up :usize = last_octet_partial + $octetnum;
		let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;

		if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {
			/*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)",
				$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);
			println!("    byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */
			/*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum,
				$selfarg.byte_cursor, $selfarg.bit_cursor,
				&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +
				1 + octetnum_rounded_up]);// */
			if $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() {
				//println!(" => Out of bounds :\\");
				return Err(());
			}
			let buf = &$selfarg.inner[$selfarg.byte_cursor
				.. $selfarg.byte_cursor + 1 + octetnum_rounded_up];
			let mut res :$rettype = buf[0] as $rettype;
			res >>= $selfarg.bit_cursor;
			let mut cur_bit_cursor = 8 - $selfarg.bit_cursor;
			for i in 1 .. octetnum_rounded_up {
				res |= (buf[i] as $rettype) << cur_bit_cursor;
				cur_bit_cursor += 8;
			}
			let last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after);
			res |= (last_bits as $rettype) << cur_bit_cursor;
			$selfarg.byte_cursor += octetnum_rounded_up;
			$selfarg.bit_cursor = bit_cursor_after;
			//println!(" => {:?}", res);
			Ok(res)
		} else {
			/*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={})",
				$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);
			println!("    byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */
			/*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum,
				$selfarg.byte_cursor, $selfarg.bit_cursor,
				&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +
				octetnum_rounded_up]);// */
			if $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() {
				//println!(" => Out of bounds :\\");
				return Err(());
			}
			let buf = &$selfarg.inner[$selfarg.byte_cursor ..
				$selfarg.byte_cursor + octetnum_rounded_up];
			let mut res :$rettype = buf[0] as $rettype;
			res >>= $selfarg.bit_cursor;
			if $bitnum <= 8 {
				res &= mask_bits($bitnum) as $rettype;
			}
			let mut cur_bit_cursor = 8 - $selfarg.bit_cursor;
			for i in 1 .. octetnum_rounded_up - 1 {
				res |= (buf[i] as $rettype) << cur_bit_cursor;
				cur_bit_cursor += 8;
			}
			if $bitnum > 8 {
				let last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after);
				res |= (last_bits as $rettype) << cur_bit_cursor;
			}
			$selfarg.byte_cursor += $octetnum;
			$selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize;
			$selfarg.bit_cursor = bit_cursor_after;
			//println!(" => {:?}", res);
			Ok(res)
		}
	}};
}

// The main macro to peek bit aligned
// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)
macro_rules! bpc_peek_body {
	($rettype:ident, $bitnum:expr, $octetnum:expr, $selfarg:expr) => {{
		let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;
		let octetnum_rounded_up :usize = last_octet_partial + $octetnum;
		let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;

		if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {
			/*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={}+1)",
				$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);
			println!("    byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */
			/*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum,
				$selfarg.byte_cursor, $selfarg.bit_cursor,
				&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +
				1 + octetnum_rounded_up]);// */
			if $selfarg.byte_cursor + 1 + octetnum_rounded_up > $selfarg.inner.len() {
				//println!(" => Out of bounds :\\");
				return Err(());
			}
			let buf = &$selfarg.inner[$selfarg.byte_cursor
				.. $selfarg.byte_cursor + 1 + octetnum_rounded_up];
			let mut res :$rettype = buf[0] as $rettype;
			res >>= $selfarg.bit_cursor;
			let mut cur_bit_cursor = 8 - $selfarg.bit_cursor;
			for i in 1 .. octetnum_rounded_up {
				res |= (buf[i] as $rettype) << cur_bit_cursor;
				cur_bit_cursor += 8;
			}
			let last_bits = buf[octetnum_rounded_up] & mask_bits(bit_cursor_after);
			res |= (last_bits as $rettype) << cur_bit_cursor;
			//println!(" => {:?}", res);
			Ok(res)
		} else {
			/*println!("Reading {} bits (octetnum={}, last_partial={}, total_touched={})",
				$bitnum, $octetnum, last_octet_partial, $octetnum + last_octet_partial);
			println!("    byte_c={}; bit_c={}", $selfarg.byte_cursor, $selfarg.bit_cursor);// */
			/*print!("Reading {} bits (byte_c={}; bit_c={}) [] = {:?}", $bitnum,
				$selfarg.byte_cursor, $selfarg.bit_cursor,
				&$selfarg.inner[$selfarg.byte_cursor .. $selfarg.byte_cursor +
				octetnum_rounded_up]);// */
			if $selfarg.byte_cursor + octetnum_rounded_up > $selfarg.inner.len() {
				//println!(" => Out of bounds :\\");
				return Err(());
			}
			let buf = &$selfarg.inner[$selfarg.byte_cursor ..
				$selfarg.byte_cursor + octetnum_rounded_up];
			let mut res :$rettype = buf[0] as $rettype;
			res >>= $selfarg.bit_cursor;
			if $bitnum <= 8 {
				res &= mask_bits($bitnum) as $rettype;
			}
			let mut cur_bit_cursor = 8 - $selfarg.bit_cursor;
			for i in 1 .. octetnum_rounded_up - 1 {
				res |= (buf[i] as $rettype) << cur_bit_cursor;
				cur_bit_cursor += 8;
			}
			if $bitnum > 8 {
				let last_bits = buf[octetnum_rounded_up - 1] & bmask_bits(bit_cursor_after);
				res |= (last_bits as $rettype) << cur_bit_cursor;
			}
			//println!(" => {:?}", res);
			Ok(res)
		}
	}};
}

// The main macro to advance bit aligned
// Note that `$octetnum` is the number of octets in $bitnum ($bitnum / 8 rounded down)
macro_rules! bpc_advance_body {
( $bitnum:expr, $octetnum:expr, $selfarg:expr ) => { {
	let last_octet_partial :usize = ($bitnum as i8 - $octetnum as i8 * 8 > 0) as usize;
	let octetnum_rounded_up :usize = last_octet_partial + $octetnum;
	let bit_cursor_after = ($selfarg.bit_cursor + $bitnum) % 8;

	if ($selfarg.bit_cursor + $bitnum) as usize > 8 * octetnum_rounded_up {
		$selfarg.byte_cursor += octetnum_rounded_up;
		$selfarg.bit_cursor = bit_cursor_after;
		//println!(" => {:?}", res);
		Ok(())
	} else {
		$selfarg.byte_cursor += $octetnum;
		$selfarg.byte_cursor += ($selfarg.bit_cursor == 8 - ($bitnum % 8)) as usize;
		$selfarg.bit_cursor = bit_cursor_after;
		//println!(" => {:?}", res);
		Ok(())
	}
} }
}

macro_rules! uk_reader {
	($fnname:ident, $rettype:ident, $bitnum:expr, $octetnum:expr) => {
		#[inline]
		pub fn $fnname(&mut self) -> Result<$rettype, ()> {
			bpc_read_body!($rettype, $bitnum, $octetnum, self)
		}
	};
}

macro_rules! ik_reader {
	($fnname:ident, $rettype:ident, $bitnum_of_rettype:expr, $bitnum:expr, $octetnum:expr) => {
		#[inline]
		pub fn $fnname(&mut self) -> Result<$rettype, ()> {
			Ok(sign_extend!(try!(
				bpc_read_body!($rettype, $bitnum, $octetnum, self)),
				$rettype, $bitnum_of_rettype, $bitnum))
		}
	};
}

macro_rules! ik_dynamic_reader {
	($fnname:ident, $rettype:ident, $bitnum_of_rettype:expr) => {
		#[inline]
		pub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> {
			let octet_num :usize = (bit_num / 8) as usize;
			assert!(bit_num <= $bitnum_of_rettype);
			Ok(sign_extend!(try!(
				bpc_read_body!($rettype, bit_num, octet_num, self)),
				$rettype, $bitnum_of_rettype, bit_num))
		}
	}
}

macro_rules! uk_dynamic_reader {
	($fnname:ident, $rettype:ident, $bit_num_max:expr) => {
		#[inline]
		pub fn $fnname(&mut self, bit_num :u8) -> Result<$rettype, ()> {
			let octet_num :usize = (bit_num / 8) as usize;
			if bit_num == 0 {
				// TODO: one day let bpc_read_body handle this,
				// if its smartly doable in there.
				// For why it is required, see comment in the
				// test_bitpacking_reader_empty function.
				return Ok(0);
			}
			assert!(bit_num <= $bit_num_max);
			bpc_read_body!($rettype, bit_num, octet_num, self)
		}
	};
}

fn float32_unpack(val :u32) -> f32 {
	let sgn = val & 0x80000000;
	let exp = (val & 0x7fe00000) >> 21;
	let mantissa = (val & 0x1fffff) as f64;
	let signed_mantissa = if sgn != 0 {
		-mantissa
	} else {
		mantissa
	};
	return signed_mantissa as f32 * (exp as f32 - 788.0).exp2();
}

#[test]
fn test_float_32_unpack() {
	// Values were printed out from what stb_vorbis
	// calculated for this function from a test file.
	assert_eq!(float32_unpack(1611661312),      1.000000);
	assert_eq!(float32_unpack(1616117760),      5.000000);
	assert_eq!(float32_unpack(1618345984),     11.000000);
	assert_eq!(float32_unpack(1620115456),     17.000000);
	assert_eq!(float32_unpack(1627381760),    255.000000);
	assert_eq!(float32_unpack(3759144960),     -1.000000);
	assert_eq!(float32_unpack(3761242112),     -2.000000);
	assert_eq!(float32_unpack(3763339264),     -4.000000);
	assert_eq!(float32_unpack(3763601408),     -5.000000);
	assert_eq!(float32_unpack(3765436416),     -8.000000);
	assert_eq!(float32_unpack(3765829632),    -11.000000);
	assert_eq!(float32_unpack(3768451072),    -30.000000);
	assert_eq!(float32_unpack(3772628992),   -119.000000);
	assert_eq!(float32_unpack(3780634624),  -1530.000000);
}

#[test]
fn test_float_32_unpack_issue_24() {
	// Regression test for issue #24, a
	// mismatch in decoded output for audio_simple_with_error.ogg
	// and singlemap-test.ogg.
	// The values are taken from the codebook_delta_value and
	// codebook_minimum_value values of the singlemap-test.ogg file.
	// The expected values come from stb_vorbis.
	assert_eq!(float32_unpack(1628434432), 255.0);
	assert_eq!(float32_unpack(1621655552), 17.0);
	assert_eq!(float32_unpack(1619722240), 11.0);
	assert_eq!(float32_unpack(1613234176), 1.0);
	assert_eq!(float32_unpack(3760717824), -1.0);
	assert_eq!(float32_unpack(3762814976), -2.0);
	assert_eq!(float32_unpack(3764912128), -4.0);
	assert_eq!(float32_unpack(3765043200), -5.0);
	assert_eq!(float32_unpack(3767009280), -8.0);
	assert_eq!(float32_unpack(3767205888), -11.0);
	assert_eq!(float32_unpack(3769565184), -30.0);
	assert_eq!(float32_unpack(3773751296), -119.0);
	assert_eq!(float32_unpack(3781948416), -1530.0);
}

// allow some code that is only used in the tests
#[allow(dead_code)]
impl <'a> BitpackCursor <'a> {

	/// Creates a new `BitpackCursor` for the given data array
	pub fn new(arr : &'a[u8]) -> BitpackCursor {
		return BitpackCursor::<'a> { bit_cursor: 0, byte_cursor: 0, inner: arr };
	}

	// Unsigned, non-dynamic reader methods

	// u32 based

	// TODO add here if needed
	uk_reader!(read_u32, u32, 32, 4);
	// TODO add here if needed
	uk_reader!(read_u24, u32, 24, 3);
	// TODO add here if needed

	// u16 based

	uk_reader!(read_u16, u16, 16, 2);

	// TODO add here if needed
	uk_reader!(read_u13, u16, 13, 1);
	// TODO add here if needed

	// u8 based
	uk_reader!(read_u8, u8, 8, 1);
	uk_reader!(read_u7, u8, 7, 0);
	uk_reader!(read_u6, u8, 6, 0);
	uk_reader!(read_u5, u8, 5, 0);
	uk_reader!(read_u4, u8, 4, 0);
	uk_reader!(read_u3, u8, 3, 0);
	uk_reader!(read_u2, u8, 2, 0);
	uk_reader!(read_u1, u8, 1, 0);

	// Returning bool:
	#[inline]
	pub fn read_bit_flag(&mut self) -> Result<bool, ()> {
		return Ok(try!(self.read_u1()) == 1);
	}

	// Unsigned dynamic reader methods
	// They panic if you give them invalid params
	// (bit_num larger than maximum allowed bit number for the type)
	uk_dynamic_reader!(read_dyn_u8,  u8,  8);
	uk_dynamic_reader!(read_dyn_u16, u16, 16);
	uk_dynamic_reader!(read_dyn_u32, u32, 32);
	uk_dynamic_reader!(read_dyn_u64, u64, 64);

	// Signed non-dynamic reader methods

	ik_reader!(read_i32, i32, 32, 32, 4);
	// TODO add here if needed

	ik_reader!(read_i8, i8, 8, 8, 1);
	ik_reader!(read_i7, i8, 8, 7, 0);
	// TODO add here if needed

	// Signed dynamic reader methods
	// They panic if you give them invalid params
	// (bit_num larger than maximum allowed bit number for the type)
	ik_dynamic_reader!(read_dyn_i8,  i8,  8);
	ik_dynamic_reader!(read_dyn_i16, i16, 16);
	ik_dynamic_reader!(read_dyn_i32, i32, 32);

	// Float reading methods

	/// Reads a single floating point number in the vorbis-float32 format
	pub fn read_f32(&mut self) -> Result<f32, ()> {
		let val = try!(self.read_u32());
		Ok(float32_unpack(val))
	}

	/// Peeks 8 bits of non read yet content without advancing the reader
	#[inline]
	pub fn peek_u8(&self) -> Result<u8, ()> {
		bpc_peek_body!(u8, 8, 1, self)
	}

	// Advances the reader by the given number of bits (up to 8).
	pub fn advance_dyn_u8(&mut self, bit_num :u8) -> Result<(), ()> {
		let octet_num :usize = (bit_num / 8) as usize;
		if bit_num == 0 {
			// TODO: one day let bpc_advance_body handle this,
			// if its smartly doable in there.
			// For why it is required, see comment in the
			// test_bitpacking_reader_empty function.
			return Ok(());
		}
		assert!(bit_num <= 8);
		bpc_advance_body!(bit_num, octet_num, self)
	}

	/// Reads a huffman word using the codebook abstraction
	pub fn read_huffman(&mut self, tree :&VorbisHuffmanTree) -> Result<u32, ()> {
		//let mut c :usize = 0;
		//let mut w :usize = 0;
		let mut iter = match self.peek_u8() {
			Ok(data) => match tree.lookup_peeked_data(8, data as u32) {
				PeekedDataLookupResult::Iter(advance, iter) => {
					try!(self.advance_dyn_u8(advance));
					iter
				},
				PeekedDataLookupResult::PayloadFound(advance, payload) => {
					try!(self.advance_dyn_u8(advance));
					return Ok(payload);
				},
			},
			Err(_) => tree.iter(),
		};

		loop {
			let b = try!(self.read_bit_flag());
			/*
			c +=1;
			w >>= 1;
			w |= (b as usize) << 63;
			// Put this into the Some arm of the match below in order to debug:
			{print!("({}:{}:{}) ", w >> (64 - c), v, c); }
			// */
			match iter.next(b) {
				Some(v) => return Ok(v),
				None => (),
			}
		}
	}
}

#[test]
fn test_bitpacking_reader_static() {
	// Test vectors taken from Vorbis I spec, section 2.1.6
	let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_u4().unwrap(),  12);
	assert_eq!(cur.read_u3().unwrap(),  7);
	assert_eq!(cur.read_u7().unwrap(),  17);
	assert_eq!(cur.read_u13().unwrap(), 6969);
}

#[test]
fn test_bitpacking_reader_dynamic() {
	// Test vectors taken from Vorbis I spec, section 2.1.6
	let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_dyn_u8(4).unwrap(),   12);
	assert_eq!(cur.read_dyn_u8(3).unwrap(),   7);
	assert_eq!(cur.read_dyn_u16(7).unwrap(),  17);
	assert_eq!(cur.read_dyn_u16(13).unwrap(), 6969);

	// Regression test for bug
	let test_arr = &[93, 92];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_dyn_u32(10).unwrap(), 93);
}

#[test]
fn test_bitpacking_reader_empty() {
	// Same as the normal bitpacking test
	// but with some additional empty reads.
	//
	// This is expected to happen by the vorbis spec.
	// For example, the mode_number read in the audio packet
	// decode at first position may be 0 bit long (if there
	// is only one mode, ilog([vorbis_mode_count] - 1) is zero).

	let test_arr = &[0b11111100, 0b01001000, 0b11001110, 0b00000110];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_dyn_u8(4).unwrap(),   12);
	assert_eq!(cur.read_dyn_u8(0).unwrap(),   0);
	assert_eq!(cur.read_dyn_u8(0).unwrap(),   0);
	assert_eq!(cur.read_dyn_u8(3).unwrap(),   7);
	assert_eq!(cur.read_dyn_u8(0).unwrap(),   0);
	assert_eq!(cur.read_dyn_u16(7).unwrap(),  17);
	assert_eq!(cur.read_dyn_u16(0).unwrap(),   0);
	assert_eq!(cur.read_dyn_u16(0).unwrap(),   0);
	assert_eq!(cur.read_dyn_u16(13).unwrap(), 6969);
	assert_eq!(cur.read_dyn_u16(0).unwrap(),   0);
}

#[test]
fn test_bitpacking_reader_byte_aligned() {
	// Check that bitpacking readers work with "normal" byte aligned types:
	let test_arr = &[0x00, 0x00, 0x00, 0x00, 0x01];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_dyn_u32(32).unwrap(), 0);
	assert_eq!(cur.read_dyn_u8(8).unwrap(),   1);

	// We not just check here whether it works for byte aligned
	// "normal" (non-dynamic) reader methods, we also check
	// whether, after reading first one, then seven bits,
	// it "gets back" to byte alignment (and increases the byte ctr)
	let test_arr = &[0x09, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01];
	let mut cur = BitpackCursor::new(test_arr);
	assert_eq!(cur.read_u1().unwrap(), 1);
	assert_eq!(cur.read_u7().unwrap(), 4);
	assert_eq!(cur.read_i8().unwrap(), 2);
	assert_eq!(cur.read_u32().unwrap(), 0);
	assert_eq!(cur.read_u8().unwrap(), 1);
}

#[test]
fn test_capture_pattern_nonaligned() {
	// Regression test from test OGG file
	// Tests for proper codebook capture
	// pattern reading.
	//
	// The OGG vorbis capture pattern
	// is a three octet (24 bits) value.
	//
	// The first block tests capture pattern
	// reading in a byte aligned scenario.
	// The actually problematic part was
	// the second block: it tests capture
	// pattern reading in a non-aligned
	// situation.

	let capture_pattern_arr = &[0x42, 0x43, 0x56];
	let mut cur = BitpackCursor::new(capture_pattern_arr);
	assert_eq!(cur.read_u24().unwrap(), 0x564342);

	let test_arr = &[0x28, 0x81, 0xd0, 0x90, 0x55, 0x00, 0x00];
	let mut cur = BitpackCursor::new(test_arr);
	cur.read_u5().unwrap(); // some value we are not interested in
	cur.read_u5().unwrap(); // some value we are not interested in
	assert_eq!(cur.read_u4().unwrap(), 0);
	assert_eq!(cur.read_u24().unwrap(), 0x564342);
	// Ensure that we incremented by only three bytes, not four
	assert_eq!(cur.read_u16().unwrap(), 1);
}


================================================
FILE: src/capi.rs
================================================
use std::os::raw::c_int;
use std::slice::from_raw_parts;
use std::ptr::null_mut;

use header::{read_header_setup, //read_header_comment,
	read_header_ident, IdentHeader, //CommentHeader,
	SetupHeader};
use audio::{PreviousWindowRight, read_audio_packet_generic};

/// Main Decoder State
///
/// It is created by `lewton_context_from_extradata` by passing a xiph-laced extradate bundle
pub struct LewtonContext {
	pwr :PreviousWindowRight,

	ident_hdr :IdentHeader,
	//comment_hdr :CommentHeader,
	setup_hdr :SetupHeader,
}

fn read_xiph_lacing(arr :&mut &[u8]) -> Option<u64> {
	let mut r = 0;
	loop {
		if arr.len() == 0 {
			return None;
		}
		let v = arr[0] as u64;
		*arr = &arr[1..];
		r += v;
		if v < 255 {
			return Some(r);
		}
	}
}

impl LewtonContext {
	fn from_extradata(mut extradata :&[u8]) -> Option<Self> {
		// We must start with a 2 as per matroska encapsulation spec
		if extradata.len() == 0 || extradata[0] != 2 {
			return None
		}
		extradata = &extradata[1..];
		let ident_len = read_xiph_lacing(&mut extradata)? as usize;
		let comment_len = read_xiph_lacing(&mut extradata)? as usize;

		let ident_hdr = read_header_ident(&extradata[0..ident_len]).ok()?;
		extradata = &extradata[ident_len..];
		//let comment_hdr = read_header_comment(&extradata[0..comment_len]).ok()?;
		extradata = &extradata[comment_len..];
		let setup_hdr = read_header_setup(extradata, ident_hdr.audio_channels,
			(ident_hdr.blocksize_0, ident_hdr.blocksize_1))
			.ok()?;
		Some(LewtonContext {
			pwr : PreviousWindowRight::new(),

			ident_hdr,
			//comment_hdr,
			setup_hdr,
		})
	}
}

/// A multichannel vector of samples
///
/// It is produced by `lewton_decode_packet`
///
/// Use `lewton_samples_count` to retrieve the number of samples available in each channel
/// Use `lewton_samples_channels` to retrieve the number of channels
/// Use `lewton_samples_for_channel_f32` to retrieve a reference to the data present in the
/// channel
///
/// use `lewton_samples_drop()` to deallocate the memory
pub struct LewtonSamples(Vec<Vec<f32>>);

/// Create a LewtonContext from an extradata buffer
///
/// Returns either NULL or a newly allocated LewtonContext
#[no_mangle]
pub unsafe extern fn lewton_context_from_extradata(
		data :*const u8, len :usize) -> *mut LewtonContext {
	if data.is_null() {
		return null_mut();
	}
	let extradata = from_raw_parts(data, len);
	if let Some(cx) = LewtonContext::from_extradata(extradata) {
		let boxed = Box::new(cx);
		Box::into_raw(boxed)
	} else {
		null_mut()
	}
}

/// Reset the Decoder to support seeking.
#[no_mangle]
pub unsafe extern fn lewton_context_reset(ctx :*mut LewtonContext) {
	(*ctx).pwr = PreviousWindowRight::new();
}

/// Decode a packet to LewtonSamples when possible
///
/// Returns 0 on success, non-zero if no samples can be produced
#[no_mangle]
pub unsafe extern fn lewton_decode_packet(ctx :*mut LewtonContext,
		pkt :*const u8, len: usize,
		sample_out :*mut *mut LewtonSamples) -> c_int {
	if pkt.is_null() || ctx.is_null() || sample_out.is_null() {
		return 1;
	}
	let pkt = from_raw_parts(pkt, len);
	let decoded = read_audio_packet_generic(&(*ctx).ident_hdr,
			&(*ctx).setup_hdr, &pkt, &mut (*ctx).pwr);
	let decoded = if let Ok(v) = decoded {
		v
	} else {
		return 2;
	};
	let boxed = Box::new(LewtonSamples(decoded));
	*sample_out = Box::into_raw(boxed);
	return 0;
}

/// Provide the number of samples present in each channel
#[no_mangle]
pub unsafe extern fn lewton_samples_count(samples :*const LewtonSamples) -> usize {
	(*samples).0
		.get(0)
		.map(|v| v.len())
		.unwrap_or(0)
}

/// Provide a reference to the channel sample data
pub unsafe extern fn lewton_samples_f32(samples :*const LewtonSamples, channel :usize) -> *const f32 {
	(*samples).0
		.get(channel)
		.map(|v| v.as_ptr())
		.unwrap_or(std::ptr::null())
}

#[no_mangle]
pub unsafe extern fn lewton_samples_drop(samples :*mut LewtonSamples) {
	std::mem::drop(Box::from_raw(samples));
}

#[no_mangle]
pub unsafe extern fn lewton_context_drop(ctx :*mut LewtonContext) {
	std::mem::drop(Box::from_raw(ctx));
}


================================================
FILE: src/header.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

/*!
Header decoding

This module takes care of decoding of the three vorbis headers:

1. Identification
2. Comment
3. Setup

It builds only on the internal bitpacking layer and the internal
huffman tree handling mod. Everything else about the headers is
decoded in this mod.
*/

use std::error;
use std::fmt;
use std::io::{Cursor, ErrorKind, Read, Error};
use std::string::FromUtf8Error;
use byteorder::{ReadBytesExt, LittleEndian};
use header_cached::{CachedBlocksizeDerived, compute_bark_map_cos_omega};
use bitpacking::BitpackCursor;
use huffman_tree::{VorbisHuffmanTree, HuffmanError};

/// Errors that can occur during Header decoding
#[derive(Debug)]
#[derive(PartialEq)]
pub enum HeaderReadError {
	EndOfPacket,
	/// If the passed data don't start with the "vorbis"
	/// capture pattern, this error is returned.
	NotVorbisHeader,
	UnsupportedVorbisVersion,
	/// If the header violates the vorbis spec
	HeaderBadFormat,
	/// The given packet indeed seems to be a vorbis header,
	/// but it looks like it is a different header type than
	/// the function it was passed to.
	///
	/// It is not guaranteed that the type is a valid header type.
	HeaderBadType(u8),
	/// The given packet does not seem to be a header as per vorbis spec,
	/// instead it seems to be an audio packet.
	HeaderIsAudio,
	Utf8DecodeError,
	/// If the needed memory isn't addressable by us
	///
	/// This error is returned if a calculation yielded a higher value for
	/// an internal buffer size that doesn't fit into the platform's address range.
	/// Note that if we "simply" encounter an allocation failure (OOM, etc),
	/// we do what libstd does in these cases: crash.
	///
	/// This error is not automatically an error of the passed data,
	/// but rather is due to insufficient decoder hardware.
	BufferNotAddressable,
}

// For the () error type returned by the bitpacking layer
// TODO that type choice was a bit unfortunate,
// perhaps one day fix this
impl From<()> for HeaderReadError {
	fn from(_ :()) -> HeaderReadError {
		HeaderReadError::EndOfPacket
	}
}

impl From<HuffmanError> for HeaderReadError {
	fn from(_ :HuffmanError) -> HeaderReadError {
		HeaderReadError::HeaderBadFormat
	}
}

impl From<Error> for HeaderReadError {
	fn from(err :Error) -> HeaderReadError {
		match err.kind() {
			ErrorKind::UnexpectedEof => HeaderReadError::EndOfPacket,
			_ => panic!("Non EOF Error occured when reading from Cursor<&[u8]>: {}", err),
		}
	}
}

impl From<FromUtf8Error> for HeaderReadError {
	fn from(_ :FromUtf8Error) -> HeaderReadError {
		HeaderReadError::Utf8DecodeError
	}
}

impl error::Error for HeaderReadError {}

impl fmt::Display for HeaderReadError {
	fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
		let description = match self {
			HeaderReadError::EndOfPacket => "End of packet reached.",
			HeaderReadError::NotVorbisHeader => "The packet is not a vorbis header",
			HeaderReadError::UnsupportedVorbisVersion => "The vorbis version is not supported",
			HeaderReadError::HeaderBadFormat => "Invalid header",
			HeaderReadError::HeaderBadType(_) => "Invalid/unexpected header type",
			HeaderReadError::HeaderIsAudio => "Packet seems to be audio",
			HeaderReadError::Utf8DecodeError => "UTF-8 decoding error",
			HeaderReadError::BufferNotAddressable => "Requested to create buffer of non-addressable size",
		};
		write!(fmt, "{}", description)
	}
}

/// Macro to convert values of any unsigned integral non-usize type to
/// usize, and then check whether there had been any losses due to conversion.
///
/// If there were, it will return the BufferNotAddressable error.
macro_rules! convert_to_usize {
( $val:expr, $val_type:ident ) => { {
	let converted :usize = $val as usize;
	if $val != converted as $val_type {
		try!(Err(HeaderReadError::BufferNotAddressable));
	}
	converted
}}
}

// Internal function, tries to find out whether the
// data returned by rdr belong to a vorbis header
// On success it returns Some(n) with n as packet type
// (you must check that n from 1,3,5)
macro_rules! read_header_begin_body {
( $rdr:expr ) => { {
	let res = try!($rdr.read_u8());
	if res & 1 == 0 {
		// This is an audio packet per vorbis spec, if anything.
		// (audio packets have their first bit set to 0,
		// header packets have it set to 1)
		try!(Err(HeaderReadError::HeaderIsAudio));
	}
	let is_vorbis =
		try!($rdr.read_u8()) == 0x76 && // 'v'
		try!($rdr.read_u8()) == 0x6f && // 'o'
		try!($rdr.read_u8()) == 0x72 && // 'r'
		try!($rdr.read_u8()) == 0x62 && // 'b'
		try!($rdr.read_u8()) == 0x69 && // 'i'
		try!($rdr.read_u8()) == 0x73;   // 's'
	if !is_vorbis {
		try!(Err(HeaderReadError::NotVorbisHeader));
	}
	return Ok(res);
}}
}
fn read_header_begin(rdr :&mut BitpackCursor) -> Result<u8, HeaderReadError> {
	read_header_begin_body!(rdr)
}
fn read_header_begin_cursor(rdr :&mut Cursor<&[u8]>) -> Result<u8, HeaderReadError> {
	read_header_begin_body!(rdr)
}


#[test]
fn test_read_hdr_begin() {
	// Only tests flawed header begins, correct headers
	// are tested later by the test methods for the headers

	// Flawed ident header (see char before the /**/)
	let test_arr = &[0x01, 0x76, 0x6f, 0x72,
	0x62, 0x69, 0x72, /**/ 0x00, 0x00, 0x00, 0x00, 0x02,
	0x44, 0xac, 0x00,      0x00, 0x00, 0x00, 0x00, 0x00,
	0x80, 0xb5, 0x01,      0x00, 0x00, 0x00, 0x00, 0x00,
	0xb8, 0x01];
	let mut rdr :BitpackCursor = BitpackCursor::new(test_arr);
	assert_eq!(read_header_begin(&mut rdr), Err(HeaderReadError::NotVorbisHeader));
}

/// The set of the three Vorbis headers
pub type HeaderSet = (IdentHeader, CommentHeader, SetupHeader);

/**
Representation for the identification header

The identification header is the first of the three
headers inside each vorbis stream.

It covers basic information about the stream.
*/
#[derive(Clone)]
pub struct IdentHeader {
	/// The number of audio channels in the stream
	pub audio_channels :u8,
	/// The sample rate of the stream
	pub audio_sample_rate :u32,
	/// The maximum bit rate of the stream
	///
	/// Note that this value is only a hint
	/// and may be off by a large amount.
	pub bitrate_maximum :i32,
	/// The nominal bit rate of the stream
	///
	/// Note that this value is only a hint
	/// and may be off by a large amount.
	pub bitrate_nominal :i32,
	/// The minimum bit rate of the stream
	///
	/// Note that this value is only a hint
	/// and may be off by a large amount.
	pub bitrate_minimum :i32,
	pub blocksize_0 :u8,
	pub blocksize_1 :u8,
	pub(crate) cached_bs_derived :[CachedBlocksizeDerived; 2],
}

/**
Reading the Identification header

If it returns Err(sth) when being called with the first packet in a stream,
the whole stream is to be considered undecodable as per the Vorbis spec.
The function returns Err(`HeaderReadError::HeaderBadType`) if the header type
doesn't match the ident header.
*/
pub fn read_header_ident(packet :&[u8]) -> Result<IdentHeader, HeaderReadError> {
	let mut rdr = BitpackCursor::new(packet);
	let hd_id = try!(read_header_begin(&mut rdr));
	if hd_id != 1 {
		try!(Err(HeaderReadError::HeaderBadType(hd_id)));
	}
	let vorbis_version = try!(rdr.read_u32());
	if vorbis_version != 0 {
		try!(Err(HeaderReadError::UnsupportedVorbisVersion));
	}
	let audio_channels = try!(rdr.read_u8());
	let audio_sample_rate = try!(rdr.read_u32());
	let bitrate_maximum = try!(rdr.read_i32());
	let bitrate_nominal = try!(rdr.read_i32());
	let bitrate_minimum = try!(rdr.read_i32());
	let blocksize_0 = try!(rdr.read_u4());
	let blocksize_1 = try!(rdr.read_u4());
	let framing = try!(rdr.read_u8());
	if blocksize_0 < 6 || blocksize_0 > 13 ||
			blocksize_1 < 6 || blocksize_1 > 13 ||
			(framing != 1) || blocksize_0 > blocksize_1 ||
			audio_channels == 0 || audio_sample_rate == 0 {
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let hdr :IdentHeader = IdentHeader {
		audio_channels,
		audio_sample_rate,
		bitrate_maximum,
		bitrate_nominal,
		bitrate_minimum,
		blocksize_0,
		blocksize_1,
		cached_bs_derived : [
			CachedBlocksizeDerived::from_blocksize(blocksize_0),
			CachedBlocksizeDerived::from_blocksize(blocksize_1),
		],
	};
	return Ok(hdr);
}

#[test]
fn test_read_header_ident() {
	// Valid ident header
	let test_arr = &[0x01, 0x76, 0x6f, 0x72,
	0x62, 0x69, 0x73, 0x00, 0x00, 0x00, 0x00, 0x02,
	0x44, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x80, 0xb5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
	0xb8, 0x01];
	let hdr = read_header_ident(test_arr).unwrap();
	assert_eq!(hdr.audio_channels, 2);
	assert_eq!(hdr.audio_sample_rate, 0x0000ac44);
	assert_eq!(hdr.bitrate_maximum, 0);
	assert_eq!(hdr.bitrate_nominal, 0x0001b580);
	assert_eq!(hdr.bitrate_minimum, 0);
	assert_eq!(hdr.blocksize_0, 8);
	assert_eq!(hdr.blocksize_1, 11);
}

/**
Representation of the comment header

The comment header is the second of the three
headers inside each vorbis stream.

It contains text comment metadata
about the stream, encoded as key-value pairs,
and the vendor name.
*/
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct CommentHeader {
	/// An identification string of the
	/// software/library that encoded
	/// the stream.
	pub vendor :String,
	/// A key-value list of the comments
	/// attached to the stream.
	pub comment_list :Vec<(String, String)>,
}

/**
Reading the Comment header

You should call this function with the second packet in the stream.

The function does not check whether the comment field names consist
of characters `0x20` through `0x7D` (`0x3D` excluded), as the vorbis
spec requires.
*/
pub fn read_header_comment(packet :&[u8]) -> Result<CommentHeader, HeaderReadError> {
	let mut rdr = Cursor::new(packet);
	let hd_id = try!(read_header_begin_cursor(&mut rdr));
	if hd_id != 3 {
		try!(Err(HeaderReadError::HeaderBadType(hd_id)));
	}
	// First read the vendor string
	let vendor_length = try!(rdr.read_u32::<LittleEndian>()) as usize;
	let mut vendor_buf = vec![0; vendor_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as "unsafe" by rustc.
	try!(rdr.read_exact(&mut vendor_buf));
	let vendor = try!(String::from_utf8(vendor_buf));

	// Now read the comments
	let comment_count = try!(rdr.read_u32::<LittleEndian>()) as usize;
	let mut comment_list = Vec::with_capacity(comment_count);
	for _ in 0 .. comment_count {
		let comment_length = try!(rdr.read_u32::<LittleEndian>()) as usize;
		let mut comment_buf = vec![0; comment_length]; // TODO fix this, we initialize memory for NOTHING!!! Out of some reason, this is seen as "unsafe" by rustc.
		try!(rdr.read_exact(&mut comment_buf));
		let comment = match String::from_utf8(comment_buf) {
			Ok(comment) => comment,
			// Uncomment for closer compliance with the spec.
			// The spec explicitly states that the comment entries
			// should be UTF-8 formatted, however it seems that other
			// decoder libraries tolerate non-UTF-8 formatted strings
			// in comments. This has led to some files circulating
			// with such errors inside. If we deny to decode such files,
			// lewton would be the odd one out. Thus we just
			// gracefully ignore them.
			Err(_) => continue,
		};
		let eq_idx = match comment.find("=") {
			Some(k) => k,
			// Uncomment for closer compliance with the spec.
			// It appears that some ogg files have fields without a = sign in the comments.
			// Well there is not much we can do but gracefully ignore their stuff.
			None => continue // try!(Err(HeaderReadError::HeaderBadFormat))
		};
		let (key_eq, val) = comment.split_at(eq_idx + 1);
		let (key, _) = key_eq.split_at(eq_idx);
		comment_list.push((String::from(key), String::from(val)));
	}
	let framing = try!(rdr.read_u8());
	if framing != 1 {
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let hdr :CommentHeader = CommentHeader {
		vendor,
		comment_list,
	};
	return Ok(hdr);
}

#[derive(Clone)]
pub(crate) struct Codebook {
	pub codebook_dimensions :u16,

	// None if codebook_lookup_type == 0
	pub codebook_vq_lookup_vec :Option<Vec<f32>>,

	pub codebook_huffman_tree :VorbisHuffmanTree,
}

#[derive(Clone)]
pub(crate) struct Residue {
	pub residue_type :u8,
	pub residue_begin :u32,
	pub residue_end :u32,
	pub residue_partition_size :u32,
	pub residue_classifications :u8,
	pub residue_classbook :u8,
	pub residue_books :Vec<ResidueBook>,
}

#[derive(Clone)]
pub(crate) struct Mapping {
	pub mapping_magnitudes :Vec<u8>,
	pub mapping_angles :Vec<u8>,
	pub mapping_mux :Vec<u8>,
	pub mapping_submap_floors :Vec<u8>,
	pub mapping_submap_residues :Vec<u8>,
}

#[derive(Clone)]
pub(crate) struct ModeInfo {
	pub mode_blockflag :bool,
	pub mode_mapping :u8,
}

#[derive(Clone)]
pub(crate) enum Floor {
	TypeZero(FloorTypeZero),
	TypeOne(FloorTypeOne),
}

#[derive(Clone)]
pub(crate) struct FloorTypeZero {
	pub floor0_order :u8,
	pub floor0_amplitude_bits :u8,
	pub floor0_amplitude_offset :u8,
	pub floor0_number_of_books :u8,
	pub floor0_book_list :Vec<u8>,
	pub cached_bark_cos_omega :[Vec<f32>; 2],
}

#[derive(Clone)]
pub(crate) struct FloorTypeOne {
	pub floor1_multiplier :u8,
	pub floor1_partition_class :Vec<u8>,
	pub floor1_class_dimensions :Vec<u8>,
	pub floor1_class_subclasses :Vec<u8>,
	pub floor1_subclass_books :Vec<Vec<i16>>,
	pub floor1_class_masterbooks :Vec<u8>,
	pub floor1_x_list :Vec<u32>,
	pub floor1_x_list_sorted :Vec<(usize, u32)>,
}

#[derive(Clone)]
pub(crate) struct ResidueBook {
	vals_used :u8,
	val_i :[u8; 8],
}

impl ResidueBook {
	pub fn get_val(&self, i :u8) -> Option<u8> {
		if i >= 8 {
			// This is a precondition...
			panic!("Tried to get ResidueBook value out of bounds (index = {})",
				i);
		}
		return if self.vals_used & (1 << i) > 0 {
			Some(self.val_i[i as usize])
		} else {
			None
		};
	}
	/// Reads the `ResidueBook` from a `BitpackCursor`.
	fn read_book(rdr :&mut BitpackCursor,
			vals_used :u8, codebooks :&[Codebook])
			-> Result<Self, HeaderReadError> {
		let mut val_i :[u8; 8] = [0; 8];
		for i in 0 .. 7 {
			if vals_used & (1 << i) == 0 {
				continue;
			}
			let val_entry = try!(rdr.read_u8());
			if match codebooks.get(val_entry as usize) {
				Some(v) => v.codebook_vq_lookup_vec.is_none(),
				None => true,
			} {
				// Both of the cases are forbidden by spec
				// (the codebook being out of bounds, or
				// not having a value mapping)
				try!(Err(HeaderReadError::HeaderBadFormat))
			}
			val_i[i] = val_entry;
		}
		return Ok(ResidueBook { vals_used, val_i });
	}
}

#[derive(Clone)]
pub struct SetupHeader {
	pub(crate) codebooks :Vec<Codebook>,
	pub(crate) floors :Vec<Floor>,
	pub(crate) residues :Vec<Residue>,
	pub(crate) mappings :Vec<Mapping>,
	pub(crate) modes :Vec<ModeInfo>,
}

struct CodebookVqLookup {
	codebook_lookup_type :u8,
	codebook_minimum_value :f32,
	codebook_delta_value :f32,
	codebook_sequence_p :bool,
	codebook_multiplicands :Vec<u32>,
}

/// Vector value decode for lookup
///
/// Prepares the VQ context vectors for later lookup
/// by the codebook abstraction layer.
///
/// Returns `codebook_entries` many vectors,
/// each being `codebook_dimensions` scalars wide),
/// all stored in one Vec.
fn lookup_vec_val_decode(lup :&CodebookVqLookup, codebook_entries :u32, codebook_dimensions :u16) -> Vec<f32> {
	let mut value_vectors = Vec::with_capacity(
		codebook_entries as usize * codebook_dimensions as usize);
	if lup.codebook_lookup_type == 1 {
		let codebook_lookup_values = lup.codebook_multiplicands.len();
		for lookup_offset in 0 .. codebook_entries {
			let mut last = 0.;
			let mut index_divisor = 1;
			for _ in 0 .. codebook_dimensions {
				let multiplicand_offset = (lookup_offset / index_divisor as u32) as usize %
					codebook_lookup_values;
				let vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 *
					lup.codebook_delta_value + lup.codebook_minimum_value + last;
				if lup.codebook_sequence_p {
					last = vec_elem;
				}
				value_vectors.push(vec_elem);
				index_divisor *= codebook_lookup_values;
			}
		}
	} else {
		for lookup_offset in 0 .. codebook_entries {
			let mut last = 0.;
			let mut multiplicand_offset :usize = lookup_offset as usize * codebook_dimensions as usize;
			for _ in 0 .. codebook_dimensions {
				let vec_elem = lup.codebook_multiplicands[multiplicand_offset] as f32 *
					lup.codebook_delta_value + lup.codebook_minimum_value + last;
				if lup.codebook_sequence_p {
					last = vec_elem;
				}
				value_vectors.push(vec_elem);
				multiplicand_offset += 1;
			}
		}
	}
	return value_vectors;
}


/// Small Error type for `BitpackCursor::read_huffman_vq`.
///
/// This is in order to enable calling code to distinguish
/// between the two cases of the enum. Esp. in some cases
/// the decoder might have to reject packages with the
/// NoVqLookupForCodebook variant, but have to treat EndOfPacket
/// as normal occurence.
pub(crate) enum HuffmanVqReadErr {
	EndOfPacket,
	NoVqLookupForCodebook,
}

impl <'a> BitpackCursor <'a> {
	/// Reads a huffman word using the codebook abstraction via a VQ context
	pub(crate) fn read_huffman_vq<'b>(&mut self, b :&'b Codebook) -> Result<&'b[f32], HuffmanVqReadErr> {

		let idx = match self.read_huffman(&b.codebook_huffman_tree) {
			Ok(v) => v as usize,
			Err(_) => return Err(HuffmanVqReadErr::EndOfPacket),
		};
		let codebook_vq_lookup_vec :&[f32] = match b.codebook_vq_lookup_vec.as_ref() {
			Some(ref v) => v,
			None => return Err(HuffmanVqReadErr::NoVqLookupForCodebook),
		};
		let dim = b.codebook_dimensions as usize;
		return Ok(&codebook_vq_lookup_vec[idx * dim .. (idx + 1) * dim]);
	}
}

static MAX_BASES_WITHOUT_OVERFLOW : &[u32] = &[
	0xffffffff, 0xffffffff, 0x0000ffff, 0x00000659,
	0x000000ff, 0x00000054, 0x00000028, 0x00000017,
	0x0000000f, 0x0000000b, 0x00000009, 0x00000007,
	0x00000006, 0x00000005, 0x00000004, 0x00000004,
	0x00000003, 0x00000003, 0x00000003, 0x00000003,
	0x00000003, 0x00000002, 0x00000002, 0x00000002,
	0x00000002, 0x00000002, 0x00000002, 0x00000002,
	0x00000002, 0x00000002, 0x00000002, 0x00000002];

static MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW : &[u8] = &[
	0x1f, 0x1f, 0x0f, 0x0a,
	0x07, 0x06, 0x05, 0x04,
	0x03, 0x03, 0x03, 0x02,
	0x02, 0x02, 0x02, 0x02,
	0x01, 0x01, 0x01, 0x01,
	0x01, 0x01, 0x01, 0x01,
	0x01, 0x01, 0x01, 0x01,
	0x01, 0x01, 0x01, 0x01];

// For this little function I won't include the num crate.
// precondition: base ^ exponent must not overflow.
fn exp_fast(base :u32, exponent: u8) -> u32 {
	let mut res :u32 = 1;
	let mut selfmul = base;
	for i in 0 .. 8 {
		if (1 << i) & exponent > 0 {
			res *= selfmul;
		}
		if let Some(newselfmul) = u32::checked_mul(selfmul, selfmul) {
			selfmul = newselfmul;
		} else {
			// Okay, now we have to find out
			// whether this matters or not.
			// Check whether selfmul would have been needed.
			if i < 7 && (exponent >> (i + 1)) > 0 {
				panic!("Overflow when squaring for exp_fast, \
					precondition violated!");
			}
			return res;
		}
	}
	return res;
}

/// Returns, as defined in the vorbis spec:
/// "the greatest integer for which to `[return_value]` the power of `[codebook_dimensions]` is less than or equal to `[codebook_entries]`"
/// Essentially an "nth-root" algorithm.
/// About the speed:
/// Probably its super-optimized as it uses no floats,
/// probably smarter algorithms using floats would be faster here. No idea.
/// Either way, stackoverflow gave the (great) motivation for the algorithm:
/// http://stackoverflow.com/questions/7407752
fn lookup1_values(codebook_entries :u32, codebook_dimensions :u16) -> u32 {
	if codebook_dimensions >= 32 {
		// For codebook_dimensions >= 32 we'd already overflow the u32 range if
		// we computed 2 ^ codebook_dimensions.
		// Therefore, the result must be less than 2.
		return if codebook_entries == 0 { 0 } else { 1 };
	}
	// Now do a binary search.
	// We use two static helper arrays here. Both take the
	// exponent (codebook_dimensions here) as index.
	// The first array, MAX_BASES_WITHOUT_OVERFLOW contains
	// the base that doesn't generate an overflow for the
	// given exponent.
	// The second array MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW
	// contains the number of the highest set bit in
	// the corresponding entry in MAX_BASES_WITHOUT_OVERFLOW.
	// This is the first bit that is "disputed" in the binary
	// search to follow: we check the bases to support the
	// claim by manual exponentiation.
	let max_base_bits = MAX_BASE_MAX_BITS_WITHOUT_OVERFLOW[
		codebook_dimensions as usize];
	let max_base = MAX_BASES_WITHOUT_OVERFLOW[codebook_dimensions as usize];
	let mut base_bits :u32 = 0;
	for i in 0 .. max_base_bits + 1 {
		let cur_disputed_bit :u32 = 1 << (max_base_bits - i);
		base_bits |= cur_disputed_bit;
		if max_base < base_bits ||
				exp_fast(base_bits, codebook_dimensions as u8) > codebook_entries {
			base_bits &= !cur_disputed_bit;
		}
	}
	return base_bits;
}

#[test]
fn test_lookup1_values() {
	// First, with base two:
	// 2 ^ 10 = 1024
	assert_eq!(lookup1_values(1025, 10), 2);
	assert_eq!(lookup1_values(1024, 10), 2);
	assert_eq!(lookup1_values(1023, 10), 1);

	// Now, the searched base is five:
	// 5 ^ 5 = 3125
	assert_eq!(lookup1_values(3126, 5), 5);
	assert_eq!(lookup1_values(3125, 5), 5);
	assert_eq!(lookup1_values(3124, 5), 4);

	// Now some exotic tests (edge cases :p):
	assert_eq!(lookup1_values(1, 1), 1);
	assert_eq!(lookup1_values(0, 15), 0);
	assert_eq!(lookup1_values(0, 0), 0);
	assert_eq!(lookup1_values(1, 0), std::u32::MAX);
	assert_eq!(lookup1_values(400, 0), std::u32::MAX);
}

/// Reads a codebook which is part of the setup header packet.
fn read_codebook(rdr :&mut BitpackCursor) -> Result<Codebook, HeaderReadError> {

	// 1. Read the sync pattern
	let sync_pattern = try!(rdr.read_u24());
	if sync_pattern != 0x564342 {
		try!(Err(HeaderReadError::HeaderBadFormat));
	}

	// 2. Read the _dimension, _entries fields and the ordered bitflag
	let codebook_dimensions = try!(rdr.read_u16());
	let codebook_entries = try!(rdr.read_u24());
	let ordered = try!(rdr.read_bit_flag());

	// 3. Read the codeword lengths
	let mut codebook_codeword_lengths = Vec::with_capacity(
		convert_to_usize!(codebook_entries, u32));
	if !ordered {
		let sparse = try!(rdr.read_bit_flag());
		for _ in 0 .. codebook_entries {
			let length = if sparse {
				let flag = try!(rdr.read_bit_flag());
				if flag {
					try!(rdr.read_u5()) + 1
				} else {
					/* The spec here asks that we should mark that the
					entry is unused. But 0 already fulfills this purpose,
					as everywhere else its guaranteed that the length is > 0.
					No messing with Option<T> needed here :) */
					0
				}
			} else {
				try!(rdr.read_u5()) + 1
			};
			codebook_codeword_lengths.push(length);
		}
	} else {
		let mut current_entry :u32 = 0;
		let mut current_length = try!(rdr.read_u5()) + 1;
		while current_entry < codebook_entries {
			let number = try!(rdr.read_dyn_u32(
				::ilog((codebook_entries - current_entry) as u64)));
			for _ in current_entry .. current_entry + number {
				codebook_codeword_lengths.push(current_length);
			}
			current_entry += number;
			current_length += 1;
			if current_entry as u32 > codebook_entries {
				try!(Err(HeaderReadError::HeaderBadFormat));
			}
		}
	}

	// 4. Read the vector lookup table
	let codebook_lookup_type = try!(rdr.read_u4());
	if codebook_lookup_type > 2 {
		// Not decodable per vorbis spec
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let codebook_lookup :Option<CodebookVqLookup> =
	if codebook_lookup_type == 0 {
		None
	} else {
		let codebook_minimum_value = try!(rdr.read_f32());
		let codebook_delta_value = try!(rdr.read_f32());
		let codebook_value_bits = try!(rdr.read_u4()) + 1;
		let codebook_sequence_p = try!(rdr.read_bit_flag());
		let codebook_lookup_values :u64 = if codebook_lookup_type == 1 {
			 lookup1_values(codebook_entries, codebook_dimensions) as u64
		} else {
			codebook_entries as u64 * codebook_dimensions as u64
		};
		let mut codebook_multiplicands = Vec::with_capacity(
			convert_to_usize!(codebook_lookup_values, u64));
		for _ in 0 .. codebook_lookup_values {
			codebook_multiplicands.push(try!(rdr.read_dyn_u32(codebook_value_bits)));
		}
		Some(CodebookVqLookup {
			codebook_lookup_type,
			codebook_minimum_value,
			codebook_delta_value,
			codebook_sequence_p,
			codebook_multiplicands,
		})
	};
	let codebook_vq_lookup_vec = codebook_lookup.as_ref().map(|lup| {
		lookup_vec_val_decode(lup,
			codebook_entries, codebook_dimensions)
	});

	return Ok(Codebook {
		codebook_dimensions,
		codebook_vq_lookup_vec,
		codebook_huffman_tree : try!(VorbisHuffmanTree::load_from_array(&codebook_codeword_lengths)),
	});
}

/// Reads a Floor which is part of the setup header packet.
/// The `codebook_cnt` param is required to check for compliant streams
fn read_floor(rdr :&mut BitpackCursor, codebook_cnt :u16, blocksizes :(u8, u8)) ->
		Result<Floor, HeaderReadError> {
	let floor_type = try!(rdr.read_u16());
	match floor_type {
		0 => {
			let floor0_order = try!(rdr.read_u8());
			let floor0_rate = try!(rdr.read_u16());
			let floor0_bark_map_size = try!(rdr.read_u16());
			let floor0_amplitude_bits = try!(rdr.read_u6());
			if floor0_amplitude_bits > 64 {
				// Unfortunately the audio decoder part
				// doesn't support values > 64 because rust has no
				// 128 bit integers yet.
				// TODO when support is added, remove this
				// check.
				try!(Err(HeaderReadError::HeaderBadFormat));
			}
			let floor0_amplitude_offset = try!(rdr.read_u8());
			let floor0_number_of_books = try!(rdr.read_u4()) + 1;
			let mut floor0_book_list = Vec::with_capacity(
				convert_to_usize!(floor0_number_of_books, u8));
			for _ in 0 .. floor0_number_of_books {
				let value = try!(rdr.read_u8());
				if value as u16 > codebook_cnt {
					try!(Err(HeaderReadError::HeaderBadFormat));
				}
				floor0_book_list.push(value);
			}
			Ok(Floor::TypeZero(FloorTypeZero {
				floor0_order,
				floor0_amplitude_bits,
				floor0_amplitude_offset,
				floor0_number_of_books,
				floor0_book_list,
				cached_bark_cos_omega : [
					compute_bark_map_cos_omega(1 << (blocksizes.0 - 1),
						floor0_rate, floor0_bark_map_size),
					compute_bark_map_cos_omega(1 << (blocksizes.1 - 1),
						floor0_rate, floor0_bark_map_size),
				]
			}))
		},
		1 => {
			let floor1_partitions = try!(rdr.read_u5());
			let mut maximum_class :i8 = -1;
			let mut floor1_partition_class_list = Vec::with_capacity(
				floor1_partitions as usize);
			for _ in 0 .. floor1_partitions {
				let cur_class = try!(rdr.read_u4());
				maximum_class = if cur_class as i8 > maximum_class
					{ cur_class as i8 } else { maximum_class };
				floor1_partition_class_list.push(cur_class);
			}

			// TODO one day try out whether its more performant
			// to have these two arrays in one, its wasteful to allocate
			// 16 bit so that one can store 5 bits.
			let mut floor1_class_dimensions = Vec::with_capacity((maximum_class + 1) as usize);
			let mut floor1_class_subclasses = Vec::with_capacity((maximum_class + 1) as usize);

			let mut floor1_subclass_books = Vec::with_capacity((maximum_class + 1) as usize);

			let mut floor1_class_masterbooks = Vec::with_capacity((maximum_class + 1) as usize);
			for _ in 0 .. maximum_class + 1 {
				floor1_class_dimensions.push(try!(rdr.read_u3()) + 1);
				let cur_subclass = try!(rdr.read_u2());
				floor1_class_subclasses.push(cur_subclass);
				if cur_subclass != 0 {
					let cur_masterbook = try!(rdr.read_u8());
					if cur_masterbook as u16 >= codebook_cnt {
						// undecodable as per spec
						try!(Err(HeaderReadError::HeaderBadFormat));
					}
					floor1_class_masterbooks.push(cur_masterbook);
				} else {
					// Some value... This never gets read,
					// but Rust requires everything to be initialized,
					// we can't increase the counter without initialisation.
					floor1_class_masterbooks.push(0);
				}
				let cur_books_cnt :u8 = 1 << cur_subclass;
				let mut cur_books = Vec::with_capacity(cur_books_cnt as usize);
				for _ in 0 .. cur_books_cnt {
					// The fact that we need i16 here (and shouldn't do
					// wrapping sub) is only revealed if you read the
					// "packet decode" part of the floor 1 spec...
					let cur_book = (try!(rdr.read_u8()) as i16) - 1;
					if cur_book >= codebook_cnt as i16 {
						// undecodable as per spec
						try!(Err(HeaderReadError::HeaderBadFormat));
					}
					cur_books.push(cur_book);
				}
				floor1_subclass_books.push(cur_books);
			}
			let floor1_multiplier = try!(rdr.read_u2()) + 1;
			let rangebits = try!(rdr.read_u4());
			let mut floor1_values :u16 = 2;
			// Calculate the count before doing anything else
			for cur_class_num in &floor1_partition_class_list {
				floor1_values += floor1_class_dimensions[*cur_class_num as usize] as u16;
			}
			if floor1_values > 65 {
				// undecodable as per spec
				try!(Err(HeaderReadError::HeaderBadFormat));
			}
			let mut floor1_x_list = Vec::with_capacity(floor1_values as usize);
			floor1_x_list.push(0);
			floor1_x_list.push(1u32 << rangebits);
			for cur_class_num in &floor1_partition_class_list {
				for _ in 0 .. floor1_class_dimensions[*cur_class_num as usize] {
					floor1_x_list.push(try!(rdr.read_dyn_u32(rangebits)));
				}
			}
			// Now do an uniqueness check on floor1_x_list
			// to check decodability.
			let mut floor1_x_list_sorted = floor1_x_list.iter().cloned()
				.enumerate().collect::<Vec<_>>();
			floor1_x_list_sorted.sort_by(|a, b| a.1.cmp(&b.1));
			// 0 is guaranteed to be in the list,
			// and due to sorting it will be first.
			let mut last = 1;
			for el in &floor1_x_list_sorted {
				if el.1 == last {
					// duplicate entry found
					// undecodable as per spec
					try!(Err(HeaderReadError::HeaderBadFormat));
				}
				last = el.1;
			}

			// Only now return the result
			Ok(Floor::TypeOne(FloorTypeOne {
				floor1_multiplier,
				floor1_partition_class : floor1_partition_class_list,
				floor1_class_dimensions,
				floor1_class_subclasses,
				floor1_subclass_books,
				floor1_class_masterbooks,
				floor1_x_list,
				floor1_x_list_sorted,

			}))
		},
		// Type greater than 1 is error condition per spec
		_ => Err(HeaderReadError::HeaderBadFormat),
	}
}

/// Reads a Residue which is part of the setup header packet.
/// The `codebook_cnt` param is required to check for compliant streams
fn read_residue(rdr :&mut BitpackCursor, codebooks :&[Codebook])
		-> Result<Residue, HeaderReadError> {
	let residue_type = try!(rdr.read_u16());
	if residue_type > 2 {
		// Undecodable by spec
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let residue_begin = try!(rdr.read_u24());
	let residue_end = try!(rdr.read_u24());
	if residue_begin > residue_end {
		// If residue_begin < residue_end, we'll get
		// errors in audio parsing code.
		// As the idea of residue end being before begin
		// sounds quite wrong anyway, we already error
		// earlier, in header parsing code.
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let residue_partition_size = try!(rdr.read_u24()) + 1;
	let residue_classifications = try!(rdr.read_u6()) + 1;
	let residue_classbook = try!(rdr.read_u8());
	// Read the bitmap pattern:
	let mut residue_cascade = Vec::with_capacity(residue_classifications as usize);
	for _ in 0 .. residue_classifications {
		let mut high_bits = 0;
		let low_bits = try!(rdr.read_u3());
		let bitflag = try!(rdr.read_bit_flag());
		if bitflag {
			high_bits = try!(rdr.read_u5());
		}
		residue_cascade.push((high_bits << 3) | low_bits);
	}

	let mut residue_books = Vec::with_capacity(residue_classifications as usize);
	// Read the list of book numbers:
	for cascade_entry in &residue_cascade {
		residue_books.push(try!(
			ResidueBook::read_book(rdr, *cascade_entry, codebooks)));
	}
	if residue_classbook as usize >= codebooks.len() {
		// Undecodable because residue_classbook must be valid index
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	/*
	// Currently we check below condition in audio decode, following the spec,
	// section 3.3., saying that it only renders the packet that wants to use the
	// invalid codebook invalid, but not the whole stream only because there is a
	// residue in the header (which may never be used).
	if codebooks[residue_classbook as usize].codebook_vq_lookup_vec.is_none() {
		// Undecodable because residue_classbook must be valid index
		try!(Err(HeaderReadError::HeaderBadFormat));
	}*/
	return Ok(Residue {
		residue_type : residue_type as u8,
		residue_begin,
		residue_end,
		residue_partition_size,
		residue_classifications,
		residue_classbook,
		residue_books,
	});
}

/// Reads a "Mapping" which is part of the setup header packet.
fn read_mapping(rdr :&mut BitpackCursor,
		audio_chan_ilog :u8, audio_channels :u8,
		floor_count :u8, residue_count :u8)
		-> Result<Mapping, HeaderReadError> {
	let mapping_type = try!(rdr.read_u16());
	if mapping_type > 0 {
		// Undecodable per spec
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let mapping_submaps = match try!(rdr.read_bit_flag()) {
		true => try!(rdr.read_u4()) + 1,
		false => 1,
	};
	let mapping_coupling_steps = match try!(rdr.read_bit_flag()) {
		true => try!(rdr.read_u8()) as u16 + 1,
		false => 0,
	};
	let mut mapping_magnitudes = Vec::with_capacity(mapping_coupling_steps as usize);
	let mut mapping_angles = Vec::with_capacity(mapping_coupling_steps as usize);
	for _ in 0 .. mapping_coupling_steps {
		let cur_mag = try!(rdr.read_dyn_u8(audio_chan_ilog));
		let cur_angle = try!(rdr.read_dyn_u8(audio_chan_ilog));
		if (cur_angle == cur_mag) || (cur_mag >= audio_channels)
				|| (cur_angle >= audio_channels) {
			// Undecodable per spec
			try!(Err(HeaderReadError::HeaderBadFormat));
		}
		mapping_magnitudes.push(cur_mag);
		mapping_angles.push(cur_angle);
	}
	let reserved = try!(rdr.read_u2());
	if reserved != 0 {
		// Undecodable per spec
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	let mapping_mux = if mapping_submaps > 1 {
		let mut m = Vec::with_capacity(audio_channels as usize);
		for _ in 0 .. audio_channels {
			let val = try!(rdr.read_u4());
			if val >= mapping_submaps {
				// Undecodable per spec
				try!(Err(HeaderReadError::HeaderBadFormat));
			}
			m.push(val);
		};
		m
	} else {
		vec![0; audio_channels as usize]
	};
	let mut mapping_submap_floors = Vec::with_capacity(mapping_submaps as usize);
	let mut mapping_submap_residues = Vec::with_capacity(mapping_submaps as usize);
	for _ in 0 .. mapping_submaps {
		// To whom those reserved bits may concern.
		// I have discarded them!
		try!(rdr.read_u8());
		let cur_floor = try!(rdr.read_u8());
		let cur_residue = try!(rdr.read_u8());
		if cur_floor >= floor_count ||
				cur_residue >= residue_count {
			// Undecodable per spec
			try!(Err(HeaderReadError::HeaderBadFormat));
		}
		mapping_submap_floors.push(cur_floor);
		mapping_submap_residues.push(cur_residue);
	}
	return Ok(Mapping {
		mapping_magnitudes,
		mapping_angles,
		mapping_mux,
		mapping_submap_floors,
		mapping_submap_residues,
	});
}

/// Reads a ModeInfo which is part of the setup header packet.
fn read_mode_info(rdr :&mut BitpackCursor, mapping_count :u8) -> Result<ModeInfo, HeaderReadError> {
	let mode_blockflag = try!(rdr.read_bit_flag());
	let mode_windowtype = try!(rdr.read_u16());
	let mode_transformtype = try!(rdr.read_u16());
	let mode_mapping = try!(rdr.read_u8());
	// Verifying ranges
	if mode_windowtype != 0 ||
			mode_transformtype != 0 ||
			mode_mapping >= mapping_count {
		// Undecodable per spec
		try!(Err(HeaderReadError::HeaderBadFormat));
	}
	return Ok(ModeInfo {
		mode_blockflag,
		mode_mapping,
	});
}

/// Reading the setup header.
///
/// The audio channel and blocksize info needed by the function
/// can be obtained from the ident header.
pub fn read_header_setup(packet :&[u8], audio_channels :u8, blocksizes :(u8, u8)) ->
		Result<SetupHeader, HeaderReadError> {
	let mut rdr = BitpackCursor::new(packet);
	let hd_id = try!(read_header_begin(&mut rdr));
	if hd_id != 5 {
		try!(Err(HeaderReadError::HeaderBadType(hd_id)));
	}

	// Little preparation -- needed later
	let audio_chan_ilog = ::ilog((audio_channels - 1) as u64);

	//::print_u8_slice(packet);

	// 1. Read the codebooks
	let vorbis_codebook_count :u16 = try!(rdr.read_u8()) as u16 + 1;
	let mut codebooks = Vec::with_capacity(vorbis_codebook_count as usize);
	for _ in 0 .. vorbis_codebook_count {
		codebooks.push(try!(read_codebook(&mut rdr)));
	}

	// 2. Read the time domain transforms
	let vorbis_time_count :u8 = try!(rdr.read_u6()) + 1;
	for _ in 0 .. vorbis_time_count {
		if try!(rdr.read_u16()) != 0 {
			try!(Err(HeaderReadError::HeaderBadFormat));
		}
	}

	// 3. Read the floor values
	let vorbis_floor_count :u8 = try!(rdr.read_u6()) + 1;
	let mut floors = Vec::with_capacity(vorbis_floor_count as usize);
	for _ in 0 .. vorbis_floor_count {
		floors.push(try!(read_floor(&mut rdr, vorbis_codebook_count, blocksizes)));
	}

	// 4. Read the residue values
	let vorbis_residue_count :u8 = try!(rdr.read_u6()) + 1;
	let mut residues = Vec::with_capacity(vorbis_residue_count as usize);
	for _ in 0 .. vorbis_residue_count {
		residues.push(try!(read_residue(&mut rdr, &codebooks)));
	}

	// 5. Read the mappings
	let vorbis_mapping_count :u8 = try!(rdr.read_u6()) + 1;
	let mut mappings = Vec::with_capacity(vorbis_mapping_count as usize);
	for _ in 0 .. vorbis_mapping_count {
		mappings.push(try!(read_mapping(& mut rdr,
			audio_chan_ilog, audio_channels,
			vorbis_floor_count, vorbis_residue_count)));
	}

	// 6. Read the modes
	let vorbis_mode_count :u8 = try!(rdr.read_u6()) + 1;
	let mut modes = Vec::with_capacity(vorbis_mode_count as usize);
	for _ in 0 .. vorbis_mode_count {
		modes.push(try!(read_mode_info(& mut rdr, vorbis_mapping_count)));
	}

	// Now we only have to make sure the framing bit is set,
	// and we can successfully return the setup header!
	let framing :bool = try!(rdr.read_bit_flag());
	if !framing {
		try!(Err(HeaderReadError::HeaderBadFormat));
	}

	return Ok(SetupHeader {
		codebooks,
		floors,
		residues,
		mappings,
		modes,
	});
}


================================================
FILE: src/header_cached.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

/*!
Cached header info

This mod contains logic to generate and deal with
data derived from header information
that's used later in the decode process.

The caching is done to speed up decoding.
*/

#[derive(Clone)]
pub struct TwiddleFactors {
	pub a :Vec<f32>,
	pub b :Vec<f32>,
	pub c :Vec<f32>,
}

#[derive(Clone)]
pub struct CachedBlocksizeDerived {
	pub twiddle_factors : TwiddleFactors,
	pub window_slope : Vec<f32>,
	pub bitrev : Vec<u32>,
}

impl CachedBlocksizeDerived {
	pub fn from_blocksize(bs :u8) -> Self {
		CachedBlocksizeDerived {
			window_slope : generate_window((1 << (bs as u16)) >> 1),
			twiddle_factors : compute_twiddle_factors(bs),
			bitrev : compute_bitreverse(bs),
		}
	}
}

fn win_slope(x :u16, n :u16) -> f32 {
	// please note that there might be a MISTAKE
	// in how the spec specifies the right window slope
	// function. See "4.3.1. packet type, mode and window decode"
	// step 7 where it adds an "extra" pi/2.
	// The left slope doesn't have it, only the right one.
	// as stb_vorbis shares the window slope generation function,
	// The *other* possible reason is that we don't need the right
	// window for anything. TODO investigate this more.
	let v = (0.5 * std::f32::consts::PI * (x as f32 + 0.5) / n as f32).sin();
	return (0.5 * std::f32::consts::PI * v * v ).sin();
}

fn generate_window(n :u16) -> Vec<f32> {
	let mut window = Vec::with_capacity(n as usize);
	for i in 0 .. n {
		window.push(win_slope(i, n));
	}
	return window;
}

fn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors {
	let n = 1 << (blocksize as u16);

	let n2 = n >> 1;
	let n4 = n >> 2;
	let n8 = n >> 3;

	let mut a = Vec::with_capacity(n2);
	let mut b = Vec::with_capacity(n2);
	let mut c = Vec::with_capacity(n4);

	let mut k2 = 0;

	let pi_4_n = 4.0 * std::f32::consts::PI / (n as f32);
	let pi_05_n = 0.5 * std::f32::consts::PI / (n as f32);
	let pi_2_n = 2.0 * std::f32::consts::PI / (n as f32);

	for k in 0..n4 {
		a.push( f32::cos((k as f32)      * pi_4_n));
		a.push(-f32::sin((k as f32)      * pi_4_n));
		b.push( f32::cos(((k2+1) as f32) * pi_05_n) * 0.5);
		b.push( f32::sin(((k2+1) as f32) * pi_05_n) * 0.5);
		k2 += 2;
	}
	k2 = 0;
	for _ in 0..n8 {
		c.push( f32::cos(((k2 + 1) as f32) * pi_2_n));
		c.push(-f32::sin(((k2 + 1) as f32) * pi_2_n));
		k2 += 2;
	}
	return TwiddleFactors {
		a,
		b,
		c,
	};
}

fn compute_bitreverse(blocksize :u8) -> Vec<u32> {
	let ld = blocksize as u16;
	let n = 1 << blocksize;
	let n8 = n >> 3;
	let mut rev = Vec::with_capacity(n8);
	for i in 0 .. n8 {
		rev.push((::bit_reverse(i as u32) as u32 >> (32 - ld + 3)) << 2);
	}
	return rev;
}

#[test]
fn test_compute_bitreverse() {
	let br = compute_bitreverse(8);
	// The output was generated from the output of the
	// original stb_vorbis function.
	let cmp_arr = &[
		0,   64,  32,  96,
		16,  80,  48, 112,
		8,   72,  40, 104,
		24,  88,  56, 120,
		4,   68,  36, 100,
		20,  84,  52, 116,
		12,  76,  44, 108,
		28,  92,  60, 124];
	assert_eq!(br, cmp_arr);
}

#[inline]
fn bark(x :f32) -> f32 {
	13.1 * (0.00074 * x).atan() + 2.24 * (0.0000000185*x*x).atan() + 0.0001 * x
}

/// Precomputes bark map values used by floor type 0 packets
///
/// Precomputes the cos(omega) values for use by floor type 0 computation.
///
/// Note that there is one small difference to the spec: the output
/// vec is n elements long, not n+1. The last element (at index n)
/// is -1 in the spec, we lack it. Users of the result of this function
/// implementation should use it "virtually".
pub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16,
		floor0_bark_map_size :u16) -> Vec<f32> {
	let mut res = Vec::with_capacity(n as usize);
	let hfl = floor0_rate as f32 / 2.0;
	let hfl_dn = hfl / n as f32;
	let foobar_const_part = floor0_bark_map_size as f32 / bark(hfl);
	// Bark map size minus 1:
	let bms_m1 = floor0_bark_map_size as f32 - 1.0;
	let omega_factor = std::f32::consts::PI / floor0_bark_map_size as f32;
	for i in 0 .. n {
		let foobar = (bark(i as f32 * hfl_dn) * foobar_const_part).floor();
		let map_elem = foobar.min(bms_m1);
		let cos_omega = (map_elem * omega_factor).cos();
		res.push(cos_omega);
	}
	return res;
}


================================================
FILE: src/huffman_tree.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

/*!
Huffman tree unpacking and traversal

This mod contains the `VorbisHuffmanTree` struct which
can be loaded from the `codebook_codeword_lengths` array
specified for each codebook in the vorbis setup header.

Once decoding is happening, you are more interested in
the `VorbisHuffmanIter` struct which provides you with
facilities to load a value bit by bit.
*/

struct HuffTree {
	// True iff every sub-tree in this tree
	// either has two direct children or none
	even_childs :bool,
	payload :Option<u32>,
	l :Option<Box<HuffTree>>,
	r :Option<Box<HuffTree>>,
}

/*
use std::fmt;
impl fmt::Debug for HuffTree {
	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
		fn fmt_rec(s :&HuffTree, f: &mut fmt::Formatter, depth :u32) -> fmt::Result {
			macro_rules! depth_print {
			($f:ident, $depth:ident) => {
				for _ in 0..$depth {
					try!(write!($f, "| "));
				}
			}}
			if s.l.is_some() || s.r.is_some() {
				try!(writeln!(f, "ec: {:?}, pl: {:?}, LIS {:?} RIS {:?}",
					s.even_childs, s.payload, s.l.is_some(), s.r.is_some()));
			} else {
				try!(writeln!(f, "ec: {:?}, pl: {:?}", s.even_childs, s.payload));
			}
			if let Some(ref v) = s.l {
				depth_print!(f, depth);
				try!(write!(f, "LEFT "));
				try!(fmt_rec(&*v, f, depth + 1));
			}
			if let Some(ref v) = s.r {
				depth_print!(f, depth);
				try!(write!(f, "RIGT "));
				try!(fmt_rec(&*v, f, depth + 1));
			}
			return Ok(());
		}
		try!(fmt_rec(self, f, 1));
		return Ok(());
	}
} // */

impl HuffTree {
	/// Returns whether the addition was successful
	pub fn insert_rec(&mut self, payload :u32, depth :u8) -> bool {
		//print!("INSERT payload {:?} depth {:?} ", payload, depth);
		if self.payload.is_some() {
			//println!(" => OCCUPIED AS LEAF");
			return false;
		}
		if depth == 0 {
			if !(self.l.is_none() && self.r.is_none()) {
				//println!(" => INNER NODE");
				return false;
			}
			self.payload = Some(payload);
			//println!(" => ADDED");
			return true;
		}
		if self.even_childs {
			//println!(" => HAS EVEN CHILDS");
			match &mut self.l {
				&mut Some(_) => return false,
				&mut None => {
					let mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None };
					new_node.insert_rec(payload, depth - 1);
					self.l = Some(Box::new(new_node));
					self.even_childs = false;
					return true;
				}
			}
		} else {
			//println!(" => HAS NOT EVEN CHILDS");
			// First try left branch
			let left = self.l.as_mut().unwrap();
			if !left.even_childs {
				if left.insert_rec(payload, depth - 1) {
					self.even_childs = left.even_childs &&
						if let &mut Some(ref mut right) = &mut self.r.as_mut() { right.even_childs } else { false };
					return true;
				}
			}
			// Left sub tree was either full or leaf
			// Therefore, put it in the right branch now
			// As left has even_childs == true, right causes
			// us to have even_childs == false.
			return match self.r {
				Some(ref mut right) => {
					let success = right.insert_rec(payload, depth - 1);
					self.even_childs = left.even_childs && right.even_childs;
					success
				},
				None => {
					let mut new_node = HuffTree { even_childs :true, payload :None, l :None, r :None };
					let success = new_node.insert_rec(payload, depth - 1);
					self.even_childs = left.even_childs && new_node.even_childs;
					self.r = Some(Box::new(new_node));
					success
				}
			};
		}
	}
}

#[derive(Debug)]
pub enum HuffmanError {
	Overspecified,
	Underpopulated,
	InvalidSingleEntry,
}

#[derive(Clone, Copy)]
enum UnrolledLookupEntry {
	/// The specified entry was found in the lookup array
	///
	/// First param: offset by which to advance the reader
	/// Second param: the payload
	HasEntry(u8, u32),
	/// Seems the given input is inconclusive and not complete yet.
	///
	/// The argument contains a hint that is an offset inside desc_prog
	/// to help to advance the reader.
	InconclusiveWithHint(u32),
	/// Seems the given input is inconclusive and not complete yet.
	Inconclusive,
}

pub enum PeekedDataLookupResult<'l> {
	/// The supplied info is not enough to result in a payload directly.
	///
	/// First param is the number of bits to advance.
	///
	/// The returned iterator has state up to the count of bits that could be used.
	Iter(u8, VorbisHuffmanIter<'l>),
	/// The supplied info is enough to map to a payload
	///
	/// First param is the number of bits to advance. Second is payload.
	PayloadFound(u8, u32),
}

/// Huffman tree representation
#[derive(Clone)]
pub struct VorbisHuffmanTree {
	// Format: three bytes per non leaf node, one byte per leaf node.
	// First byte is the payload container,
	// second and third point to the indices inside the vector that
	// have left and right children.
	// If the node is a leaf the highest bit of the payload container 0,
	// if it has children the bit is 1. If its a leaf the lower 31 bits of the
	// payload container form the actual payload.
	desc_prog :Vec<u32>,

	unrolled_entries :[UnrolledLookupEntry; 256],
}

impl VorbisHuffmanTree {
	/// Constructs a new `VorbisHuffmanTree` instance from the passed array,
	/// like the vorbis spec demands.
	///
	/// Returns the resulting tree if the array results in a valid (neither
	/// underspecified nor overspecified) tree.
	pub fn load_from_array(codebook_codeword_lengths :&[u8]) -> Result<VorbisHuffmanTree, HuffmanError> {
		// First step: generate a simple tree representing the
		// Huffman tree
		let mut simple_tree = HuffTree { even_childs :true, payload :None, l :None, r :None };
		let mut cnt :usize = 0;
		let mut last_valid_idx = None;
		for (i, &codeword_length) in codebook_codeword_lengths.iter().enumerate() {
			if codeword_length == 0 {
				continue;
			}
			cnt += 1;
			last_valid_idx = Some(i);
			if !simple_tree.insert_rec(i as u32, codeword_length) {
				try!(Err(HuffmanError::Overspecified)) /* Overspecified, can't be put into tree */
			}
		}
		//println!("The tree:\n{:?}", simple_tree);

		// Single entry codebook special handling
		if cnt == 1 {
			let decoded = last_valid_idx.unwrap();
			let encoded_len = codebook_codeword_lengths[decoded];
			if encoded_len == 1 {
				// Return a vorbis tree that returns decoded for any single bit input
				return Ok(VorbisHuffmanTree {
					desc_prog :vec![1u32 << 31, 3, 3, decoded as u32],
					unrolled_entries :[
						UnrolledLookupEntry::HasEntry(1, decoded as u32); 256
					],
				});
			} else {
				// Single entry codebooks must have 1 as their only length entry
				try!(Err(HuffmanError::InvalidSingleEntry))
			}
		}

		if !simple_tree.even_childs {
			try!(Err(HuffmanError::Underpopulated)); /* Underpopulated */
		}

		// Second step: generate the actual desc_prog
		// by pre_order traversal of the tree.
		//
		// The general advantage of this approach over one with only the simple tree
		// is better cache locality and less memory requirements (at least after the
		// setup with the simple tree).
		let mut desc_prog = Vec::with_capacity(cnt);
		fn traverse(tree :& HuffTree, desc_prog :&mut Vec<u32>) -> u32 {
			let cur_pos = desc_prog.len() as u32;
			let has_children = tree.l.is_some() || tree.r.is_some();

			let entry = ((has_children as u32) << 31) | tree.payload.unwrap_or(0);
			//println!("push node (w_children : {:?}) at {:?} : {:?}", has_children, cur_pos, entry);
			desc_prog.push(entry);

			if has_children {
				desc_prog.push(0);
				desc_prog.push(0);
				desc_prog[cur_pos as usize + 1] =
					traverse(tree.l.as_ref().unwrap(), desc_prog);
				/*println!("left child of node {:?}: at {:?}", cur_pos,
					desc_prog[cur_pos as usize + 1]);// */
				desc_prog[cur_pos as usize + 2] =
					traverse(tree.r.as_ref().unwrap(), desc_prog);
				/*println!("right child of node {:?}: at {:?}", cur_pos,
					desc_prog[cur_pos as usize + 2]);// */
			}
			return cur_pos;
		}
		assert_eq!(traverse(&simple_tree, &mut desc_prog), 0);

		// Third step: generate unrolled entries array
		// Also by pre_order traversal.
		//
		// This gives us a speedup over desc_prog as reading the unrolled
		// entries should involve less branching and less lookups overall.
		let mut unrolled_entries = [UnrolledLookupEntry::Inconclusive; 256];
		fn uroll_traverse(tree :& HuffTree,
				unrolled_entries :&mut [UnrolledLookupEntry; 256],
				prefix :u32, prefix_idx :u8,
				desc_prog :&[u32], desc_prog_idx :u32) {
			let has_children = tree.l.is_some() || tree.r.is_some();

			if has_children {
				// There are children.
				// We'd like to recurse deeper. Can we?
				if prefix_idx == 8 {
					// No we can't.
					// The tree is too deep.
					unrolled_entries[prefix as usize] =
						UnrolledLookupEntry::InconclusiveWithHint(desc_prog_idx);
				} else {
					// Recurse deeper.
					uroll_traverse(tree.l.as_ref().unwrap(),
						unrolled_entries,
						prefix + (0 << prefix_idx), prefix_idx + 1,
						desc_prog, desc_prog[desc_prog_idx as usize + 1]);
					uroll_traverse(tree.r.as_ref().unwrap(),
						unrolled_entries,
						prefix + (1 << prefix_idx), prefix_idx + 1,
						desc_prog, desc_prog[desc_prog_idx as usize + 2]);
				}
			} else {
				// No children, fill the entries in the range according to
				// the prefix we have.
				let payload = tree.payload.unwrap();
				let it = 1 << prefix_idx;
				let mut i = prefix as usize;
				for _ in 1 .. (1u16 << (8 - prefix_idx)) {
					unrolled_entries[i] =
						UnrolledLookupEntry::HasEntry(prefix_idx, payload);
					i += it;
				}
			}
		}
		if cnt > 0 {
			uroll_traverse(&simple_tree,
				&mut unrolled_entries, 0, 0, &desc_prog, 0);
		}

		// Now we are done, return the result
		return Ok(VorbisHuffmanTree {
			desc_prog,
			unrolled_entries,
		});
	}

	/// Returns an iterator over this tree.
	pub fn iter<'l>(&'l self) -> VorbisHuffmanIter<'l> {
		return VorbisHuffmanIter { desc_prog :&self.desc_prog, pos :0 };
	}

	/// Resolves a given number of peeked bits.
	///
	/// Returns whether the data given is enough to uniquely identify a
	/// tree element, or whether only an iterator that's progressed by
	/// a given amount can be returned. Also, info is returned about how
	/// far the reader can be advanced.
	pub fn lookup_peeked_data<'l>(&'l self, bit_count :u8, peeked_data :u32)
			-> PeekedDataLookupResult<'l> {
		if bit_count > 8 {
			panic!("Bit count {} larger than allowed 8", bit_count);
		}
		use self::UnrolledLookupEntry::*;
		use self::PeekedDataLookupResult::*;
		return match self.unrolled_entries[peeked_data as usize] {
			// If cnt_to_remove is bigger than bit_count the result is inconclusive.
			// Return in this case.
			HasEntry(cnt_to_remove, payload) if cnt_to_remove <= bit_count
				=> PayloadFound(cnt_to_remove, payload),
			InconclusiveWithHint(hint)
				=> Iter(8, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : hint }),
			_
				=> Iter(0, VorbisHuffmanIter { desc_prog : &self.desc_prog, pos : 0 }),
		};
	}
}

/// Iterator on the Huffman tree
pub struct VorbisHuffmanIter<'a> {
	desc_prog :&'a Vec<u32>,
	pos :u32,
}

impl<'a> VorbisHuffmanIter<'a> {
	/// Iterate one level deeper inside the tree.
	/// Returns `Some(p)` if it encounters a leaf with a payload p,
	/// None if it only processed an inner node.
	///
	/// Inner nodes don't carry payloads in huffman trees.
	///
	/// If this function encounters a leaf, it automatically resets
	/// the iterator to its starting state.
	///
	/// # Panics
	///
	/// Panics if the vorbis huffman treee is empty. It has to be found out
	/// what to do if the huffman tree is empty, whether to reject the stream,
	/// or whether to do sth else. Finding this out is a TODO.
	pub fn next(&mut self, bit :bool) -> Option<u32> {
		// Assertion test for the paranoid and testing, comment out if you are:
		/*let cur_entry = self.desc_prog[self.pos as usize];
		assert!((cur_entry & (1u32 << 31)) != 0);*/

		//print!("With bit {:?}, pos {:?} becomes pos ", bit, self.pos);
		self.pos = self.desc_prog[self.pos as usize + 1 + bit as usize];
		//print!("{:?}", self.pos);
		let child = self.desc_prog[self.pos as usize];
		if (child & (1u32 << 31)) != 0 {
			//println!(" => None");
			// child has children
			return None;
		} else {
			//println!(" => Some({:?})", child);
			// child has no children, it's a leaf
			self.pos = 0;
			return Some(child);
		}
	}
}

#[cfg(test)]
impl VorbisHuffmanTree {
	fn iter_test(&self, path :u32, path_len :u8, expected_val :u32) {
		let mut itr = self.iter();
		for i in 1 .. path_len {
			assert_eq!(itr.next((path & (1 << (path_len - i))) != 0), None);
		}
		assert_eq!(itr.next((path & 1) != 0), Some(expected_val));
	}
}

#[test]
fn test_huffman_tree() {
	// Official example from the vorbis spec section 3.2.1
	let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3]).unwrap();

	tree.iter_test(0b00, 2, 0);
	tree.iter_test(0b0100, 4, 1);
	tree.iter_test(0b0101, 4, 2);
	tree.iter_test(0b0110, 4, 3);
	tree.iter_test(0b0111, 4, 4);
	tree.iter_test(0b10, 2, 5);
	tree.iter_test(0b110, 3, 6);
	tree.iter_test(0b111, 3, 7);

	// Some other example
	// we mostly test the length (max 32) here
	VorbisHuffmanTree::load_from_array(&[
		1,   2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
		17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 32]).unwrap();
}

#[test]
fn test_issue_8() {
	// regression test for issue 8
	// make sure that it doesn't panic.
	let _ = VorbisHuffmanTree::load_from_array(&[0; 625]);
}

#[test]
fn test_under_over_spec() {
	// All trees base on the official example from the vorbis spec section 3.2.1
	// but with modifications to under- or overspecify them

	// underspecified
	let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3/*, 3*/]);
	assert!(tree.is_err());

	// underspecified
	let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, /*4,*/ 2, 3, 3]);
	assert!(tree.is_err());

	// overspecified
	let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 4, 4, 2, 3, 3/*]*/,3]);
	assert!(tree.is_err());
}

#[test]
fn test_single_entry_huffman_tree() {
	// Special testing for single entry codebooks, as required by the vorbis spec
	let tree = VorbisHuffmanTree::load_from_array(&[1]).unwrap();
	tree.iter_test(0b0, 1, 0);
	tree.iter_test(0b1, 1, 0);

	let tree = VorbisHuffmanTree::load_from_array(&[0, 0, 1, 0]).unwrap();
	tree.iter_test(0b0, 1, 2);
	tree.iter_test(0b1, 1, 2);

	let tree = VorbisHuffmanTree::load_from_array(&[2]);
	assert!(tree.is_err());
}

#[test]
fn test_unordered_huffman_tree() {
	// Reordered the official example from the vorbis spec section 3.2.1
	//
	// Ensuring that unordered huffman trees work as well is important
	// because the spec does not disallow them, and unordered
	// huffman trees appear in "the wild".
	let tree = VorbisHuffmanTree::load_from_array(&[2, 4, 4, 2, 4, 4, 3, 3]).unwrap();

	tree.iter_test(0b00, 2, 0);
	tree.iter_test(0b0100, 4, 1);
	tree.iter_test(0b0101, 4, 2);
	tree.iter_test(0b10, 2, 3);
	tree.iter_test(0b0110, 4, 4);
	tree.iter_test(0b0111, 4, 5);
	tree.iter_test(0b110, 3, 6);
	tree.iter_test(0b111, 3, 7);
}

#[test]
fn test_extracted_huffman_tree() {
	// Extracted from a real-life vorbis file.
	VorbisHuffmanTree::load_from_array(&[
	5,  6, 11, 11, 11, 11, 10, 10, 12, 11,  5,  2, 11,  5,  6,  6,
	7,  9, 11, 13, 13, 10,  7, 11,  6,  7,  8,  9, 10, 12, 11,  5,
	11, 6,  8,  7,  9, 11, 14, 15, 11,  6,  6,  8,  4,  5,  7,  8,
	10,13, 10,  5,  7,  7,  5,  5,  6,  8, 10, 11, 10,  7,  7,  8,
	6,  5,  5,  7,  9,  9, 11,  8,  8, 11,  8,  7,  6,  6,  7,  9,
	12,11, 10, 13,  9,  9,  7,  7,  7,  9, 11, 13, 12, 15, 12, 11,
	9,  8,  8,  8]).unwrap();
}


================================================
FILE: src/imdct.rs
================================================
// Vorbis decoder written in Rust
//
// Copyright (c) 2016 est31 <MTest31@outlook.com>
// and contributors. All rights reserved.
// Licensed under MIT license, or Apache 2 license,
// at your option. Please see the LICENSE file
// attached to this source distribution for details.

// This file is a very close translation of the
// implementation of the algorithm from stb_vorbis.

use ::header_cached::CachedBlocksizeDerived;

fn imdct_step3_iter0_loop(n :usize, e :&mut[f32], i_off :usize, k_off :isize, a :&[f32]) {
	let mut a_offs = 0;
	let mut i_offs = i_off;
	let mut k_offs = i_off as isize + k_off;

	macro_rules! ee0 {
		(-$x:expr) => {e[i_offs - ($x as usize)]};
		($x:expr) => {e[i_offs + ($x as usize)]}
	}

	macro_rules! ee2 {
		(-$x:expr) => {e[(k_offs - $x) as usize]};
		($x:expr) => {e[(k_offs + $x) as usize]}
	}

	macro_rules! aa {
		($x:expr) => {a[a_offs + ($x as usize)]}
	}

	assert_eq!((n & 3), 0);

	for _ in 0 .. n >> 2 {
		let mut k00_20 = ee0![ 0] - ee2![ 0];
		let mut k01_21 = ee0![-1] - ee2![-1];
		ee0![ 0] += ee2![ 0];
		ee0![-1] += ee2![-1];
		ee2![ 0] = k00_20 * aa![0] - k01_21 * aa![1];
		ee2![-1] = k01_21 * aa![0] + k00_20 * aa![1];
		a_offs += 8;

		k00_20  = ee0![-2] - ee2![-2];
		k01_21  = ee0![-3] - ee2![-3];
		ee0![-2] += ee2![-2];
		ee0![-3] += ee2![-3];
		ee2![-2] = k00_20 * aa![0] - k01_21 * aa![1];
		ee2![-3] = k01_21 * aa![0] + k00_20 * aa![1];
		a_offs += 8;

		k00_20  = ee0![-4] - ee2![-4];
		k01_21  = ee0![-5] - ee2![-5];
		ee0![-4] += ee2![-4];
		ee0![-5] += ee2![-5];
		ee2![-4] = k00_20 * aa![0] - k01_21 * aa![1];
		ee2![-5] = k01_21 * aa![0] + k00_20 * aa![1];
		a_offs += 8;

		k00_20  = ee0![-6] - ee2![-6];
		k01_21  = ee0![-7] - ee2![-7];
		ee0![-6] += ee2![-6];
		ee0![-7] += ee2![-7];
		ee2![-6] = k00_20 * aa![0] - k01_21 * aa![1];
		ee2![-7] = k01_21 * aa![0] + k00_20 * aa![1];

		a_offs += 8;
		i_offs -= 8;
		k_offs -= 8;
	}
}

fn imdct_step3_inner_r_loop(lim :usize, e :&mut [f32],
		d0 :usize, k_off :isize, a :&[f32], k1 :usize) {
	let mut a_offs = 0;
	let mut d0_offs = d0;
	let mut k_offs = d0 as isize + k_off;

	macro_rules! e0 {
		(-$x:expr) => {e[d0_offs - ($x as usize)]};
		($x:expr) => {e[d0_offs + ($x as usize)]}
	}

	macro_rules! e2 {
		(-$x:expr) => {e[(k_offs - $x) as usize]};
		($x:expr) => {e[(k_offs + $x) as usize]}
	}

	macro_rules! aa {
		($x:expr) => {a[a_offs + ($x as usize)]}
	}

	for _ in 0 .. lim >> 2 {
		let mut k00_20 = e0![-0] - e2![-0];
		let mut k01_21 = e0![-1] - e2![-1];
		e0![-0] += e2![-0];
		e0![-1] += e2![-1];
		e2![-0] = (k00_20) * aa![0] - (k01_21) * aa![1];
		e2![-1] = (k01_21) * aa![0] + (k00_20) * aa![1];

		a_offs += k1;

		k00_20 = e0![-2] - e2![-2];
		k01_21 = e0![-3] - e2![-3];
		e0![-2] += e2![-2];
		e0![-3] += e2![-3];
		e2![-2] = (k00_20) * aa![0] - (k01_21) * aa![1];
		e2![-3] = (k01_21) * aa![0] + (k00_20) * aa![1];

		a_offs += k1;

		k00_20 = e0![-4] - e2![-4];
		k01_21 = e0![-5] - e2![-5];
		e0![-4] += e2![-4];
		e0![-5] += e2![-5];
		e2![-4] = (k00_20) * aa![0] - (k01_21) * aa![1];
		e2![-5] = (k01_21) * aa![0] + (k00_20) * aa![1];

		a_offs += k1;

		k00_20 = e0![-6] - e2![-6];
		k01_21 = e0![-7] - e2![-7];
		e0![-6] += e2![-6];
		e0![-7] += e2![-7];
		e2![-6] = (k00_20) * aa![0] - (k01_21) * aa![1];
		e2![-7] = (k01_21) * aa![0] + (k00_20) * aa![1];

		d0_offs -= 8;
		k_offs -= 8;

		a_offs += k1;
	}
}

fn imdct_step3_inner_s_loop(n :usize, e :&mut [f32], i_off :usize, k_off :isize,
		a :&[f32], a_off :usize, k0 :usize) {
	let a0 = a[0];
	let a1 = a[0+1];
	let a2 = a[0+a_off];
	let a3 = a[0+a_off+1];
	let a4 = a[0+a_off*2+0];
	let a5 = a[0+a_off*2+1];
	let a6 = a[0+a_off*3+0];
	let a7 = a[0+a_off*3+1];

	let mut i_offs = i_off;
	let mut k_offs = (i_off as isize + k_off) as usize;

	macro_rules! ee0 {
		(-$x:expr) => {e[i_offs - ($x as usize)]};
		($x:expr) => {e[i_offs + ($x as usize)]}
	}

	macro_rules! ee2 {
		(-$x:expr) => {e[k_offs - ($x as usize)]};
		($x:expr) => {e[k_offs + ($x as usize)]}
	}

	let mut i = 0;
	loop {
		let mut k00 = ee0![ 0] - ee2![ 0];
		let mut k11 = ee0![-1] - ee2![-1];
		ee0![ 0] =  ee0![ 0] + ee2![ 0];
		ee0![-1] =  ee0![-1] + ee2![-1];
		ee2![ 0] = (k00) * a0 - (k11) * a1;
		ee2![-1] = (k11) * a0 + (k00) * a1;

		k00      = ee0![-2] - ee2![-2];
		k11      = ee0![-3] - ee2![-3];
		ee0![-2] =  ee0![-2] + ee2![-2];
		ee0![-3] =  ee0![-3] + ee2![-3];
		ee2![-2] = (k00) * a2 - (k11) * a3;
		ee2![-3] = (k11) * a2 + (k00) * a3;

		k00      = ee0![-4] - ee2![-4];
		k11      = ee0![-5] - ee2![-5];
		ee0![-4] =  ee0![-4] + ee2![-4];
		ee0![-5] =  ee0![-5] + ee2![-5];
		ee2![-4] = (k00) * a4 - (k11) * a5;
		ee2![-5] = (k11) * a4 + (k00) * a5;

		k00      = ee0![-6] - ee2![-6];
		k11      = ee0![-7] - ee2![-7];
		ee0![-6] =  ee0![-6] + ee2![-6];
		ee0![-7] =  ee0![-7] + ee2![-7];
		ee2![-6] = (k00) * a6 - (k11) * a7;
		ee2![-7] = (k11) * a6 + (k00) * a7;

		i += 1;
		// we have this check instead of a for loop
		// over an iterator because otherwise we
		// overflow.
		if i >= n {
			break;
		}
		i_offs -= k0;
		k_offs -= k0;
	}
}

#[inline]
fn iter_54(zm7 :&mut [f32]) {
	// difference from stb_vorbis implementation:
	// zm7 points to z minus 7
	// (Rust disallows negative indices)

	let k00  = zm7[7] - zm7[3];
	let y0   = zm7[7] + zm7[3];
	let y2   = zm7[5] + zm7[1];
	let k22  = zm7[5] - zm7[1];

	zm7[7] = y0 + y2;      // z0 + z4 + z2 + z6
	zm7[5] = y0 - y2;      // z0 + z4 - z2 - z6

	// done with y0,y2

	let k33  = zm7[4] - zm7[0];

	zm7[3] = k00 + k33;    // z0 - z4 + z3 - z7
	zm7[1] = k00 - k33;    // z0 - z4 - z3 + z7

	// done with k33

	let k11  = zm7[6] - zm7[2];
	let y1   = zm7[6] + zm7[2];
	let y3   = zm7[4] + zm7[0];

	zm7[6] = y1 + y3;      // z1 + z5 + z3 + z7
	zm7[4] = y1 - y3;      // z1 + z5 - z3 - z7
	zm7[2] = k11 - k22;    // z1 - z5 + z2 - z6
	zm7[0] = k11 + k22;    // z1 - z5 - z2 + z6
}

fn imdct_step3_inner_s_loop_ld654(n :usize, e :&mut [f32], i_off :usize,
	a :&[f32], base_n :usize)
{
	let a_off = base_n >> 3;
	let a2 = a[a_off];

	let mut z_offs = i_off;

	let basep16 = i_off - 16 * (n - 1 as usize);

	macro_rules! z {
		(-$x:expr) => {e[z_offs - ($x as usize)]}
	}

	loop {
		let mut k00 = z![-0] - z![-8];
		let mut k11 = z![-1] - z![-9];
		z![-0] = z![-0] + z![-8];
		z![-1] = z![-1] + z![-9];
		z![-8] =  k00;
		z![-9] =  k11;

		k00     = z![ -2] - z![-10];
		k11     = z![ -3] - z![-11];
		z![ -2] = z![ -2] + z![-10];
		z![ -3] = z![ -3] + z![-11];
		z![-10] = (k00+k11) * a2;
		z![-11] = (k11-k00) * a2;

		k00     = z![-12] - z![ -4];  // reverse to avoid a unary negation
		k11     = z![ -5] - z![-13];
		z![ -4] = z![ -4] + z![-12];
		z![ -5] = z![ -5] + z![-13];
		z![-12] = k11;
		z![-13] = k00;

		k00     = z![-14] - z![ -6];  // reverse to avoid a unary negation
		k11     = z![ -7] - z![-15];
		z![ -6] = z![ -6] + z![-14];
		z![ -7] = z![ -7] + z![-15];
		z![-14] = (k00+k11) * a2;
		z![-15] = (k00-k11) * a2;

		iter_54(e.split_at_mut(z_offs - 7).1);
		iter_54(e.split_at_mut(z_offs - 7 - 8).1);
		// We need to compare with basep16 here
		// in order to prevent a possible overflow
		// in calculation of base, and in calculation
		// of z_offs.
		if z_offs <= basep16 {
			break;
		}
		z_offs -= 16;
	}
}

#[allow(dead_code)]
pub fn inverse_mdct(cached_bd :&CachedBlocksizeDerived, buffer :&mut [f32], bs :u8) {
	let n = buffer.len();
	// Pre-condition.
	assert_eq!(n, 1 << bs);

	let n2 = n >> 1;
	let n4 = n >> 2;
	let n8 = n >> 3;

	// TODO later on we might want to do Vec::with_capacity here,
	// and use buf2.push everywhere...
	let mut buf2 :Vec<f32> = vec![0.0; n2];

	let ctf = &cached_bd.twiddle_factors;
	let a :&[f32] = &ctf.a;
	let b :&[f32] = &ctf.b;
	let c :&[f32] = &ctf.c;

	macro_rules! break_if_sub_overflows {
		($i:ident, $x:expr) => {
			$i = match $i.checked_sub($x) {
				Some(v) => v,
				None => break,
			};
		}
	}

	// IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio"
	// See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' in stb_vorbis original.

	// kernel from paper


	// merged:
	//   copy and reflect spectral data
	//   step 0

	// note that it turns out that the items added together during
	// this step are, in fact, being added to themselves (as reflected
	// by step 0). inexplicable inefficiency! this became obvious
	// once I combined the passes.

	// so there's a missing 'times 2' here (for adding X to itself).
	// this propogates through linearly to the end, where the numbers
	// are 1/2 too small, and need to be compensated for.

	{
		let mut a_offs = 0;
		let mut d_offs = n2 - 2;
		let mut e_offs = 0;
		let e_stop = n2;

		macro_rules! d {
			($x:expr) => {buf2[d_offs + ($x as usize)]}
		}
		macro_rules! aa {
			($x:expr) => {a[a_offs + ($x as usize)]}
		}
		macro_rules! e {
			($x:expr) => {buffer[e_offs + ($x as usize)]}
		}

		// TODO replace the while with a for once step_by on iterators
		// is stabilized
		while e_offs != e_stop {
			d![1] = e![0] * aa![0] - e![2]*aa![1];
			d![0] = e![0] * aa![1] + e![2]*aa![0];
			d_offs -= 2;
			a_offs += 2;
			e_offs += 4;
		}

		e_offs = n2 - 3;
		loop {
			d![1] = -e![2] * aa![0] - -e![0]*aa![1];
			d![0] = -e![2] * aa![1] + -e![0]*aa![0];
			break_if_sub_overflows!(d_offs, 2);
			a_offs += 2;
			e_offs -= 4;
		}
	}


	{
		// now we use symbolic names for these, so that we can
		// possibly swap their meaning as we change which operations
		// are in place

		let u = &mut *buffer;
		let v = &mut *buf2;

		// step 2    (paper output is w, now u)
		// this could be in place, but the data ends up in the wrong
		// place... _somebody_'s got to swap it, so this is nominated
		{
			let mut a_offs = n2 - 8;
			let mut d0_offs = n4;
			let mut d1_offs = 0;
			let mut e0_offs = n4;
			let mut e1_offs = 0;

			macro_rules! aa {
				($x:expr) => {a[a_offs + ($x as usize)]}
			}
			macro_rules! d0 {
				($x:expr) => {u[d0_offs + ($x as usize)]}
			}
			macro_rules! d1 {
				($x:expr) => {u[d1_offs + ($x as usize)]}
			}
			macro_rules! e0 {
				($x:expr) => {v[e0_offs + ($x as usize)]}
			}
			macr
Download .txt
gitextract_1hjhdekp/

├── .editorconfig
├── .github/
│   └── workflows/
│       └── lewton.yml
├── .gitignore
├── .rustfmt.toml
├── CHANGELOG.md
├── Cargo.toml
├── LICENSE
├── README.md
├── cbindgen.toml
├── dev/
│   └── cmp/
│       ├── Cargo.toml
│       ├── src/
│       │   ├── lib.rs
│       │   └── main.rs
│       └── tests/
│           ├── fuzzed.rs
│           └── vals.rs
├── examples/
│   ├── perf.rs
│   └── player.rs
└── src/
    ├── audio.rs
    ├── bitpacking.rs
    ├── capi.rs
    ├── header.rs
    ├── header_cached.rs
    ├── huffman_tree.rs
    ├── imdct.rs
    ├── imdct_test.rs
    ├── inside_ogg.rs
    ├── lib.rs
    └── samples.rs
Download .txt
SYMBOL INDEX (228 symbols across 17 files)

FILE: dev/cmp/src/lib.rs
  function cmp_perf (line 22) | pub fn cmp_perf(file_path :&str) -> (Duration, Duration, usize) {
  function cmp_file_output (line 65) | pub fn cmp_file_output(file_path :&str) -> (usize, usize) {
  function cmp_output (line 79) | pub fn cmp_output<R :Read + Seek, T, F :Fn(usize, usize, usize,
  function get_asset_defs (line 238) | pub fn get_asset_defs() -> [TestAssetDef; 6] {
  function get_libnogg_asset_defs (line 274) | pub fn get_libnogg_asset_defs() -> [TestAssetDef; 32] {
  function get_xiph_asset_defs_1 (line 441) | pub fn get_xiph_asset_defs_1() -> [TestAssetDef; 5] {
  function get_xiph_asset_defs_2 (line 472) | pub fn get_xiph_asset_defs_2() -> [TestAssetDef; 5] {
  function get_xiph_asset_defs_3 (line 503) | pub fn get_xiph_asset_defs_3() -> [TestAssetDef; 5] {
  function get_xiph_asset_defs_4 (line 534) | pub fn get_xiph_asset_defs_4() -> [TestAssetDef; 7] {
  function get_xiph_asset_defs_5 (line 575) | pub fn get_xiph_asset_defs_5() -> [TestAssetDef; 5] {
  function get_fuzzed_asset_defs (line 611) | pub fn get_fuzzed_asset_defs() -> [TestAssetDef; 12] {

FILE: dev/cmp/src/main.rs
  function main (line 18) | fn main() {
  function run_perf (line 31) | fn run_perf() {
  function run_vals (line 45) | fn run_vals() {
  function run_bench (line 57) | fn run_bench() {

FILE: dev/cmp/tests/fuzzed.rs
  function test_malformed_fuzzed (line 15) | fn test_malformed_fuzzed() {
  function test_okay_fuzzed (line 40) | fn test_okay_fuzzed() {

FILE: dev/cmp/tests/vals.rs
  function test_vals (line 28) | fn test_vals() {
  function test_libnogg_vals (line 43) | fn test_libnogg_vals() {
  function test_xiph_vals_1 (line 99) | fn test_xiph_vals_1() {
  function test_xiph_vals_2 (line 113) | fn test_xiph_vals_2() {
  function test_xiph_vals_3 (line 127) | fn test_xiph_vals_3() {
  function test_xiph_vals_4 (line 141) | fn test_xiph_vals_4() {
  function test_xiph_vals_5 (line 157) | fn test_xiph_vals_5() {

FILE: examples/perf.rs
  function main (line 10) | fn main() {
  function run (line 23) | pub fn run() -> Result<(), VorbisError> {

FILE: examples/player.rs
  function main (line 19) | fn main() {
  function run (line 26) | fn run() -> Result<(), VorbisError> {

FILE: src/audio.rs
  type AudioReadError (line 27) | pub enum AudioReadError {
    method from (line 47) | fn from(_ :()) -> AudioReadError {
    method fmt (line 55) | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  type DecodedFloor (line 66) | enum DecodedFloor<'a> {
  function is_unused (line 73) | fn is_unused(&self) -> bool {
  type FloorSpecialCase (line 81) | enum FloorSpecialCase {
    method from (line 87) | fn from(_ :()) -> Self {
    method from (line 95) | fn from(e :HuffmanVqReadErr) -> Self {
  function floor_zero_decode (line 109) | fn floor_zero_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],
  function floor_zero_compute_curve (line 160) | fn floor_zero_compute_curve(cos_coefficients :&[f32], amplitude :u64,
  function floor_one_decode (line 215) | fn floor_one_decode(rdr :&mut BitpackCursor, codebooks :&[Codebook],
  function extr_neighbor (line 253) | fn extr_neighbor<F>(v :&[u32], max_idx :usize,
  function low_neighbor (line 285) | fn low_neighbor(v :&[u32], x :usize) -> (usize, u32) {
  function high_neighbor (line 290) | fn high_neighbor(v :&[u32], x :usize) -> (usize, u32) {
  function test_low_neighbor (line 295) | fn test_low_neighbor() {
  function test_high_neighbor (line 307) | fn test_high_neighbor() {
  function test_high_neighbor_ex (line 317) | fn test_high_neighbor_ex() {
  function test_high_neighbor_panic (line 344) | fn test_high_neighbor_panic() {
  function test_low_neighbor_panic (line 350) | fn test_low_neighbor_panic() {
  function render_point (line 354) | fn render_point(x0 :u32, y0 :u32, x1 :u32, y1 :u32, x :u32) -> u32 {
  function test_render_point (line 370) | fn test_render_point() {
  function floor_one_curve_compute_amplitude (line 391) | fn floor_one_curve_compute_amplitude(floor1_y :&[u32], fl :&FloorTypeOne...
  function render_line (line 503) | fn render_line(x0 :u32, y0 :u32, x1 :u32, y1 :u32, v :&mut Vec<u32>) {
  function floor_one_curve_synthesis (line 526) | fn floor_one_curve_synthesis(floor1_final_y :Vec<u32>,
  function floor_decode (line 557) | fn floor_decode<'a>(rdr :&mut BitpackCursor,
  function residue_packet_read_partition (line 587) | fn residue_packet_read_partition(rdr :&mut BitpackCursor, codebook :&Cod...
  function residue_packet_decode_inner (line 620) | fn residue_packet_decode_inner(rdr :&mut BitpackCursor, cur_blocksize :u16,
  function residue_packet_decode (line 722) | fn residue_packet_decode(rdr :&mut BitpackCursor, cur_blocksize :u16,
  function inverse_couple (line 763) | fn inverse_couple(m :f32, a :f32) -> (f32, f32) {
  function dual_mut_idx (line 781) | fn dual_mut_idx<T>(v :&mut [T], idx_a :usize, idx_b :usize)
  function dct_iv_slow (line 792) | fn dct_iv_slow(buffer :&mut [f32]) {
  function inverse_mdct_slow (line 809) | fn inverse_mdct_slow(buffer :&mut [f32]) {
  function test_imdct_slow (line 829) | fn test_imdct_slow() {
  type PreviousWindowRight (line 848) | pub struct PreviousWindowRight {
    method new (line 854) | pub fn new() -> Self {
    method is_empty (line 858) | pub fn is_empty(&self) -> bool {
  function get_decoded_sample_count (line 874) | pub fn get_decoded_sample_count(ident :&IdentHeader, setup :&SetupHeader...
  function read_audio_packet_generic (line 919) | pub fn read_audio_packet_generic<S :Samples>(ident :&IdentHeader, setup ...
  function read_audio_packet (line 1170) | pub fn read_audio_packet(ident :&IdentHeader, setup :&SetupHeader, packe...

FILE: src/bitpacking.rs
  type BitpackCursor (line 28) | pub struct BitpackCursor <'a> {
  function test_sign_extend (line 44) | fn test_sign_extend() {
  function mask_bits (line 55) | fn mask_bits(num : u8) -> u8 {
  function bmask_bits (line 61) | fn bmask_bits(num : u8) -> u8 {
  function test_mask_bits (line 66) | fn test_mask_bits() {
  function test_bmask_bits (line 79) | fn test_bmask_bits() {
  function float32_unpack (line 304) | fn float32_unpack(val :u32) -> f32 {
  function test_float_32_unpack (line 317) | fn test_float_32_unpack() {
  function test_float_32_unpack_issue_24 (line 337) | fn test_float_32_unpack_issue_24() {
  function new (line 364) | pub fn new(arr : &'a[u8]) -> BitpackCursor {
  function read_bit_flag (line 398) | pub fn read_bit_flag(&mut self) -> Result<bool, ()> {
  function read_f32 (line 429) | pub fn read_f32(&mut self) -> Result<f32, ()> {
  function peek_u8 (line 436) | pub fn peek_u8(&self) -> Result<u8, ()> {
  function advance_dyn_u8 (line 441) | pub fn advance_dyn_u8(&mut self, bit_num :u8) -> Result<(), ()> {
  function read_huffman (line 455) | pub fn read_huffman(&mut self, tree :&VorbisHuffmanTree) -> Result<u32, ...
  function test_bitpacking_reader_static (line 490) | fn test_bitpacking_reader_static() {
  function test_bitpacking_reader_dynamic (line 501) | fn test_bitpacking_reader_dynamic() {
  function test_bitpacking_reader_empty (line 517) | fn test_bitpacking_reader_empty() {
  function test_bitpacking_reader_byte_aligned (line 541) | fn test_bitpacking_reader_byte_aligned() {
  function test_capture_pattern_nonaligned (line 562) | fn test_capture_pattern_nonaligned() {

FILE: src/capi.rs
  type LewtonContext (line 13) | pub struct LewtonContext {
    method from_extradata (line 37) | fn from_extradata(mut extradata :&[u8]) -> Option<Self> {
  function read_xiph_lacing (line 21) | fn read_xiph_lacing(arr :&mut &[u8]) -> Option<u64> {
  type LewtonSamples (line 73) | pub struct LewtonSamples(Vec<Vec<f32>>);
  function lewton_context_from_extradata (line 79) | pub unsafe extern fn lewton_context_from_extradata(
  function lewton_context_reset (line 95) | pub unsafe extern fn lewton_context_reset(ctx :*mut LewtonContext) {
  function lewton_decode_packet (line 103) | pub unsafe extern fn lewton_decode_packet(ctx :*mut LewtonContext,
  function lewton_samples_count (line 124) | pub unsafe extern fn lewton_samples_count(samples :*const LewtonSamples)...
  function lewton_samples_f32 (line 132) | pub unsafe extern fn lewton_samples_f32(samples :*const LewtonSamples, c...
  function lewton_samples_drop (line 140) | pub unsafe extern fn lewton_samples_drop(samples :*mut LewtonSamples) {
  function lewton_context_drop (line 145) | pub unsafe extern fn lewton_context_drop(ctx :*mut LewtonContext) {

FILE: src/header.rs
  type HeaderReadError (line 35) | pub enum HeaderReadError {
    method from (line 69) | fn from(_ :()) -> HeaderReadError {
    method from (line 75) | fn from(_ :HuffmanError) -> HeaderReadError {
    method from (line 81) | fn from(err :Error) -> HeaderReadError {
    method from (line 90) | fn from(_ :FromUtf8Error) -> HeaderReadError {
    method fmt (line 98) | fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
  function read_header_begin (line 153) | fn read_header_begin(rdr :&mut BitpackCursor) -> Result<u8, HeaderReadEr...
  function read_header_begin_cursor (line 156) | fn read_header_begin_cursor(rdr :&mut Cursor<&[u8]>) -> Result<u8, Heade...
  function test_read_hdr_begin (line 162) | fn test_read_hdr_begin() {
  type HeaderSet (line 177) | pub type HeaderSet = (IdentHeader, CommentHeader, SetupHeader);
  type IdentHeader (line 188) | pub struct IdentHeader {
  function read_header_ident (line 221) | pub fn read_header_ident(packet :&[u8]) -> Result<IdentHeader, HeaderRea...
  function test_read_header_ident (line 262) | fn test_read_header_ident() {
  type CommentHeader (line 290) | pub struct CommentHeader {
  function read_header_comment (line 309) | pub fn read_header_comment(packet :&[u8]) -> Result<CommentHeader, Heade...
  type Codebook (line 363) | pub(crate) struct Codebook {
  type Residue (line 373) | pub(crate) struct Residue {
  type Mapping (line 384) | pub(crate) struct Mapping {
  type ModeInfo (line 393) | pub(crate) struct ModeInfo {
  type Floor (line 399) | pub(crate) enum Floor {
  type FloorTypeZero (line 405) | pub(crate) struct FloorTypeZero {
  type FloorTypeOne (line 415) | pub(crate) struct FloorTypeOne {
  type ResidueBook (line 427) | pub(crate) struct ResidueBook {
    method get_val (line 433) | pub fn get_val(&self, i :u8) -> Option<u8> {
    method read_book (line 446) | fn read_book(rdr :&mut BitpackCursor,
  type SetupHeader (line 471) | pub struct SetupHeader {
  type CodebookVqLookup (line 479) | struct CodebookVqLookup {
  function lookup_vec_val_decode (line 495) | fn lookup_vec_val_decode(lup :&CodebookVqLookup, codebook_entries :u32, ...
  type HuffmanVqReadErr (line 541) | pub(crate) enum HuffmanVqReadErr {
  function read_huffman_vq (line 548) | pub(crate) fn read_huffman_vq<'b>(&mut self, b :&'b Codebook) -> Result<...
  function exp_fast (line 585) | fn exp_fast(base :u32, exponent: u8) -> u32 {
  function lookup1_values (line 616) | fn lookup1_values(codebook_entries :u32, codebook_dimensions :u16) -> u32 {
  function test_lookup1_values (line 651) | fn test_lookup1_values() {
  function read_codebook (line 673) | fn read_codebook(rdr :&mut BitpackCursor) -> Result<Codebook, HeaderRead...
  function read_floor (line 771) | fn read_floor(rdr :&mut BitpackCursor, codebook_cnt :u16, blocksizes :(u...
  function read_residue (line 922) | fn read_residue(rdr :&mut BitpackCursor, codebooks :&[Codebook])
  function read_mapping (line 985) | fn read_mapping(rdr :&mut BitpackCursor,
  function read_mode_info (line 1060) | fn read_mode_info(rdr :&mut BitpackCursor, mapping_count :u8) -> Result<...
  function read_header_setup (line 1082) | pub fn read_header_setup(packet :&[u8], audio_channels :u8, blocksizes :...

FILE: src/header_cached.rs
  type TwiddleFactors (line 20) | pub struct TwiddleFactors {
  type CachedBlocksizeDerived (line 27) | pub struct CachedBlocksizeDerived {
    method from_blocksize (line 34) | pub fn from_blocksize(bs :u8) -> Self {
  function win_slope (line 43) | fn win_slope(x :u16, n :u16) -> f32 {
  function generate_window (line 56) | fn generate_window(n :u16) -> Vec<f32> {
  function compute_twiddle_factors (line 64) | fn compute_twiddle_factors(blocksize :u8) -> TwiddleFactors {
  function compute_bitreverse (line 101) | fn compute_bitreverse(blocksize :u8) -> Vec<u32> {
  function test_compute_bitreverse (line 113) | fn test_compute_bitreverse() {
  function bark (line 130) | fn bark(x :f32) -> f32 {
  function compute_bark_map_cos_omega (line 142) | pub fn compute_bark_map_cos_omega(n :u16, floor0_rate :u16,

FILE: src/huffman_tree.rs
  type HuffTree (line 21) | struct HuffTree {
    method insert_rec (line 66) | pub fn insert_rec(&mut self, payload :u32, depth :u8) -> bool {
  type HuffmanError (line 127) | pub enum HuffmanError {
  type UnrolledLookupEntry (line 134) | enum UnrolledLookupEntry {
  type PeekedDataLookupResult (line 149) | pub enum PeekedDataLookupResult<'l> {
  type VorbisHuffmanTree (line 164) | pub struct VorbisHuffmanTree {
    method load_from_array (line 183) | pub fn load_from_array(codebook_codeword_lengths :&[u8]) -> Result<Vor...
    method iter (line 311) | pub fn iter<'l>(&'l self) -> VorbisHuffmanIter<'l> {
    method lookup_peeked_data (line 321) | pub fn lookup_peeked_data<'l>(&'l self, bit_count :u8, peeked_data :u32)
    method iter_test (line 386) | fn iter_test(&self, path :u32, path_len :u8, expected_val :u32) {
  type VorbisHuffmanIter (line 342) | pub struct VorbisHuffmanIter<'a> {
  function next (line 362) | pub fn next(&mut self, bit :bool) -> Option<u32> {
  function test_huffman_tree (line 396) | fn test_huffman_tree() {
  function test_issue_8 (line 417) | fn test_issue_8() {
  function test_under_over_spec (line 424) | fn test_under_over_spec() {
  function test_single_entry_huffman_tree (line 442) | fn test_single_entry_huffman_tree() {
  function test_unordered_huffman_tree (line 457) | fn test_unordered_huffman_tree() {
  function test_extracted_huffman_tree (line 476) | fn test_extracted_huffman_tree() {

FILE: src/imdct.rs
  function imdct_step3_iter0_loop (line 14) | fn imdct_step3_iter0_loop(n :usize, e :&mut[f32], i_off :usize, k_off :i...
  function imdct_step3_inner_r_loop (line 73) | fn imdct_step3_inner_r_loop(lim :usize, e :&mut [f32],
  function imdct_step3_inner_s_loop (line 135) | fn imdct_step3_inner_s_loop(n :usize, e :&mut [f32], i_off :usize, k_off...
  function iter_54 (line 202) | fn iter_54(zm7 :&mut [f32]) {
  function imdct_step3_inner_s_loop_ld654 (line 234) | fn imdct_step3_inner_s_loop_ld654(n :usize, e :&mut [f32], i_off :usize,
  function inverse_mdct (line 291) | pub fn inverse_mdct(cached_bd :&CachedBlocksizeDerived, buffer :&mut [f3...
  function inverse_mdct_naive (line 662) | pub fn inverse_mdct_naive(cached_bd :&CachedBlocksizeDerived, buffer :&m...
  function test_imdct_naive (line 816) | fn test_imdct_naive() {
  function test_imdct (line 833) | fn test_imdct() {

FILE: src/imdct_test.rs
  function imdct_prepare (line 983) | pub fn imdct_prepare(arr :&[f32]) -> Vec<f32> {
  function fuzzy_compare_array (line 992) | pub fn fuzzy_compare_array(arr_a :&[f32], arr_b :&[f32],

FILE: src/inside_ogg.rs
  function read_headers (line 30) | pub fn read_headers<'a, T: Read + Seek + 'a>(rdr: &mut PacketReader<T>) ->
  type OggStreamReader (line 66) | pub struct OggStreamReader<T: Read + Seek> {
  function new (line 85) | pub fn new(rdr :T) ->
  function from_ogg_reader (line 97) | pub fn from_ogg_reader(mut rdr :PacketReader<T>) ->
  function into_inner (line 111) | pub fn into_inner(self) -> PacketReader<T> {
  function read_next_audio_packet (line 114) | fn read_next_audio_packet(&mut self) -> Result<Option<Packet>, VorbisErr...
  function read_dec_packet (line 167) | pub fn read_dec_packet(&mut self) ->
  function read_dec_packet_itl (line 183) | pub fn read_dec_packet_itl(&mut self) ->
  function read_dec_packet_generic (line 199) | pub fn read_dec_packet_generic<S :Samples>(&mut self) ->
  function dec_packet_generic (line 209) | pub fn dec_packet_generic<S :Samples>(&mut self, pck :Packet) ->
  function skip_samples_linear (line 244) | pub fn skip_samples_linear<S :Samples>(&mut self, to_skip :usize) -> Res...
  function stream_serial (line 288) | pub fn stream_serial(&self) -> u32 {
  function get_last_absgp (line 296) | pub fn get_last_absgp(&self) -> Option<u64> {
  function seek_absgp_pg (line 307) | pub fn seek_absgp_pg(&mut self, absgp :u64) -> Result<(), VorbisError> {
  type HeadersReader (line 337) | pub struct HeadersReader<T: AsyncRead> {
  function new (line 343) | pub fn new(inner :T) -> Self {
  function from_packet_reader (line 346) | pub fn from_packet_reader(pck_rd :PacketReader<T>) -> Self {
  type Item (line 355) | type Item = HeaderSet;
  type Error (line 356) | type Error = VorbisError;
  method poll (line 357) | fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
  type OggStreamReader (line 405) | pub struct OggStreamReader<T :AsyncRead> {
  function new (line 418) | pub fn new(hdr_rdr :HeadersReader<T>, hdrs :HeaderSet) -> Self {
  function from_pck_rdr (line 422) | pub fn from_pck_rdr(pck_rd :PacketReader<T>, hdrs :HeaderSet) -> Self {
  type Item (line 437) | type Item = Vec<Vec<i16>>;
  type Error (line 438) | type Error = VorbisError;
  method poll (line 440) | fn poll(&mut self) -> Poll<Option<Vec<Vec<i16>>>, VorbisError> {

FILE: src/lib.rs
  type VorbisError (line 120) | pub enum VorbisError {
    method fmt (line 130) | fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::E...
    method from (line 141) | fn from(err :audio::AudioReadError) -> VorbisError {
    method from (line 147) | fn from(err :header::HeaderReadError) -> VorbisError {
    method from (line 154) | fn from(err :OggReadError) -> VorbisError {
  function ilog (line 159) | fn ilog(val :u64) -> u8 {
  function test_ilog (line 164) | fn test_ilog() {
  function bit_reverse (line 174) | fn bit_reverse(n :u32) -> u32 {
  function print_u8_slice (line 180) | fn print_u8_slice(arr :&[u8]) {
  function print_u32_slice (line 207) | fn print_u32_slice(arr :&[u32]) {
  function print_f64_slice (line 235) | fn print_f64_slice(arr :&[f64]) {

FILE: src/samples.rs
  type Samples (line 14) | pub trait Samples {
    method num_samples (line 15) | fn num_samples(&self) -> usize;
    method truncate (line 16) | fn truncate(&mut self, limit :usize);
    method from_floats (line 17) | fn from_floats(floats :Vec<Vec<f32>>) -> Self;
    method num_samples (line 21) | fn num_samples(&self) -> usize {
    method truncate (line 24) | fn truncate(&mut self, limit :usize) {
    method from_floats (line 32) | fn from_floats(floats :Vec<Vec<f32>>) -> Self {
    method num_samples (line 49) | fn num_samples(&self) -> usize {
    method truncate (line 52) | fn truncate(&mut self, limit :usize) {
    method from_floats (line 55) | fn from_floats(floats :Vec<Vec<f32>>) -> Self {
  type InterleavedSamples (line 43) | pub struct InterleavedSamples<S :Sample> {
  type Sample (line 82) | pub trait Sample {
    method from_float (line 83) | fn from_float(fl :f32) -> Self;
    method from_float (line 87) | fn from_float(fl :f32) -> Self {
    method from_float (line 93) | fn from_float(fl :f32) -> Self {
Condensed preview — 27 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (294K chars).
[
  {
    "path": ".editorconfig",
    "chars": 164,
    "preview": "# top-most EditorConfig file\nroot = true\n\n[*]\nindent_style = tab\ntab_width = 4\nend_of_line=lf\ncharset=utf-8\ntrim_trailin"
  },
  {
    "path": ".github/workflows/lewton.yml",
    "chars": 1076,
    "preview": "name: lewton\n\non: [push, pull_request]\n\njobs:\n  build:\n\n    strategy:\n      matrix:\n        os: [macOS-latest, ubuntu-la"
  },
  {
    "path": ".gitignore",
    "chars": 40,
    "preview": "target\n*swp\ncallgrind.out.*\ntest-assets\n"
  },
  {
    "path": ".rustfmt.toml",
    "chars": 850,
    "preview": "# Note that this rustfmt file only provides rough\n# guidelines about how the style should be.\n# Right now, rustfmt is no"
  },
  {
    "path": "CHANGELOG.md",
    "chars": 5058,
    "preview": "# 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"
  },
  {
    "path": "Cargo.toml",
    "chars": 1021,
    "preview": "[workspace]\nmembers = [\"dev/cmp\"]\n\n[package]\nname = \"lewton\"\nversion = \"0.10.2\"\nauthors = [\"est31 <MTest31@outlook.com>\""
  },
  {
    "path": "LICENSE",
    "chars": 11660,
    "preview": "Copyright (c) 2016 est31 <MTest31@outlook.com> and contributors\n\nLicensed under MIT or Apache License 2.0,\nat your optio"
  },
  {
    "path": "README.md",
    "chars": 3087,
    "preview": "# lewton\n\n[![docs](https://docs.rs/lewton/badge.svg)](https://docs.rs/crate/lewton)\n[![crates.io](https://img.shields.io"
  },
  {
    "path": "cbindgen.toml",
    "chars": 206,
    "preview": "header = \"// SPDX-License-Identifier: MIT OR Apache-2.0\"\nsys_includes = [\"stddef.h\", \"stdint.h\", \"stdlib.h\"]\nno_includes"
  },
  {
    "path": "dev/cmp/Cargo.toml",
    "chars": 415,
    "preview": "[package]\nname = \"cmp\"\npublish = false\nversion = \"0.1.0\"\nlicense = \"MIT OR Apache-2.0\"\nauthors = [\"est31 <MTest31@outloo"
  },
  {
    "path": "dev/cmp/src/lib.rs",
    "chars": 27396,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016-2017 est31 <MTest31@outlook.com>\n// and contributors. All rig"
  },
  {
    "path": "dev/cmp/src/main.rs",
    "chars": 3149,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "dev/cmp/tests/fuzzed.rs",
    "chars": 1614,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2018 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "dev/cmp/tests/vals.rs",
    "chars": 5257,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "examples/perf.rs",
    "chars": 1355,
    "preview": "// Vorbis decoder written in Rust\n//\n// This example file is licensed\n// under the CC-0 license:\n// https://creativecomm"
  },
  {
    "path": "examples/player.rs",
    "chars": 2764,
    "preview": "// Vorbis decoder written in Rust\n//\n// This example file is licensed\n// under the CC-0 license:\n// https://creativecomm"
  },
  {
    "path": "src/audio.rs",
    "chars": 38857,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/bitpacking.rs",
    "chars": 20791,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/capi.rs",
    "chars": 4058,
    "preview": "use std::os::raw::c_int;\nuse std::slice::from_raw_parts;\nuse std::ptr::null_mut;\n\nuse header::{read_header_setup, //read"
  },
  {
    "path": "src/header.rs",
    "chars": 38074,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/header_cached.rs",
    "chars": 4431,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/huffman_tree.rs",
    "chars": 15798,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/imdct.rs",
    "chars": 21433,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/imdct_test.rs",
    "chars": 40587,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/inside_ogg.rs",
    "chars": 15040,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/lib.rs",
    "chars": 6142,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2016 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  },
  {
    "path": "src/samples.rs",
    "chars": 2334,
    "preview": "// Vorbis decoder written in Rust\n//\n// Copyright (c) 2019 est31 <MTest31@outlook.com>\n// and contributors. All rights r"
  }
]

About this extraction

This page contains the full source code of the RustAudio/lewton GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 27 files (266.3 KB), approximately 101.6k tokens, and a symbol index with 228 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!