lewton/
lib.rs

1// Vorbis decoder written in Rust
2//
3// Copyright (c) 2016 est31 <MTest31@outlook.com>
4// and contributors. All rights reserved.
5// Licensed under MIT license, or Apache 2 license,
6// at your option. Please see the LICENSE file
7// attached to this source distribution for details.
8
9#![cfg_attr(not(cargo_c), forbid(unsafe_code))]
10#![cfg_attr(test, deny(warnings))]
11
12/*!
13A `vorbis` decoder, written in Rust.
14
15If you "just" want to decode `ogg/vorbis` files, take a look into
16the `inside_ogg` module (make sure you haven't disabled the `ogg` feature).
17
18For lower level, per-packet usage, you can have a look at the `audio` and `header`
19modules.
20*/
21
22extern crate byteorder;
23extern crate tinyvec;
24#[cfg(feature = "ogg")]
25extern crate ogg;
26#[cfg(feature = "async_ogg")]
27#[macro_use]
28extern crate futures;
29#[cfg(feature = "async_ogg")]
30extern crate tokio_io;
31
32macro_rules! try {
33	($expr:expr) => (match $expr {
34		$crate::std::result::Result::Ok(val) => val,
35		$crate::std::result::Result::Err(err) => {
36			return Err($crate::std::convert::From::from(err));
37		}
38	})
39}
40
41/*
42// This little thing is very useful.
43macro_rules! try {
44	($expr:expr) => (match $expr {
45		$crate::std::result::Result::Ok(val) => val,
46		$crate::std::result::Result::Err(err) => {
47			panic!("Panic on Err turned on for debug reasons. Encountered Err: {:?}", err)
48		}
49	})
50}
51// */
52
53// The following macros are super useful for debugging
54
55macro_rules! record_residue_pre_inverse {
56	($residue_vectors:expr) => {
57// 		for v in $residue_vectors.iter() {
58// 			for &re in v {
59// 				println!("{}", re);
60// 			}
61// 		}
62	}
63}
64
65macro_rules! record_residue_post_inverse {
66	($residue_vectors:expr) => {
67// 		for v in $residue_vectors.iter() {
68// 			for &re in v {
69// 				println!("{}", re);
70// 			}
71// 		}
72	}
73}
74
75macro_rules! record_pre_mdct {
76	($audio_spectri:expr) => {
77// 		for v in $audio_spectri.iter() {
78// 			for &s in v {
79// 				println!("{:.5}", s);
80// 			}
81// 		}
82	}
83}
84
85macro_rules! record_post_mdct {
86	($audio_spectri:expr) => {
87// 		for v in $audio_spectri.iter() {
88// 			for &s in v {
89// 				println!("{:.4}", s);
90// 			}
91// 		}
92	}
93}
94
95pub mod header;
96mod header_cached;
97mod huffman_tree;
98mod imdct;
99#[cfg(test)]
100mod imdct_test;
101pub mod audio;
102mod bitpacking;
103#[cfg(feature = "ogg")]
104pub mod inside_ogg;
105pub mod samples;
106
107#[cfg(feature = "ogg")]
108#[doc(no_inline)]
109pub use ogg::OggReadError;
110
111#[cfg(cargo_c)]
112mod capi;
113
114#[cfg(cargo_c)]
115pub use capi::*;
116
117/// Errors that can occur during decoding
118#[derive(Debug)]
119pub enum VorbisError {
120	BadAudio(audio::AudioReadError),
121	BadHeader(header::HeaderReadError),
122	#[cfg(feature = "ogg")]
123	OggError(OggReadError),
124}
125
126impl std::error::Error for VorbisError {}
127
128impl std::fmt::Display for VorbisError {
129	fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
130		write!(fmt, "{}", match self {
131			VorbisError::BadAudio(_) => "Vorbis bitstream audio decode problem",
132			VorbisError::BadHeader(_) => "Vorbis bitstream header decode problem",
133			#[cfg(feature = "ogg")]
134			VorbisError::OggError(_) => "Ogg decode problem",
135		})
136	}
137}
138
139impl From<audio::AudioReadError> for VorbisError {
140	fn from(err :audio::AudioReadError) -> VorbisError {
141		VorbisError::BadAudio(err)
142	}
143}
144
145impl From<header::HeaderReadError> for VorbisError {
146	fn from(err :header::HeaderReadError) -> VorbisError {
147		VorbisError::BadHeader(err)
148	}
149}
150
151#[cfg(feature = "ogg")]
152impl From<OggReadError> for VorbisError {
153	fn from(err :OggReadError) -> VorbisError {
154		VorbisError::OggError(err)
155	}
156}
157
158fn ilog(val :u64) -> u8 {
159	64 - val.leading_zeros() as u8
160}
161
162#[test]
163fn test_ilog() {
164	// Uses the test vectors from the Vorbis I spec
165	assert_eq!(ilog(0), 0);
166	assert_eq!(ilog(1), 1);
167	assert_eq!(ilog(2), 2);
168	assert_eq!(ilog(3), 2);
169	assert_eq!(ilog(4), 3);
170	assert_eq!(ilog(7), 3);
171}
172
173fn bit_reverse(n :u32) -> u32 {
174	// From the stb_vorbis implementation
175	let mut nn = n;
176	nn = ((nn & 0xAAAAAAAA) >> 1) | ((nn & 0x55555555) << 1);
177	nn = ((nn & 0xCCCCCCCC) >> 2) | ((nn & 0x33333333) << 2);
178	nn = ((nn & 0xF0F0F0F0) >> 4) | ((nn & 0x0F0F0F0F) << 4);
179	nn = ((nn & 0xFF00FF00) >> 8) | ((nn & 0x00FF00FF) << 8);
180	return (nn >> 16) | (nn << 16);
181}
182
183
184#[allow(dead_code)]
185fn print_u8_slice(arr :&[u8]) {
186	if arr.len() <= 4 {
187		for a in arr {
188			print!("0x{:02x} ", a);
189		}
190		println!("");
191		return;
192	}
193	println!("[");
194	let mut i :usize = 0;
195	while i * 4 < arr.len() - 4 {
196		println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x},",
197				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);
198		i += 1;
199	}
200	match arr.len() as i64 - i as i64 * 4 {
201		1 => println!("\t0x{:02x}];", arr[i * 4]),
202		2 => println!("\t0x{:02x}, 0x{:02x}];", arr[i * 4], arr[i * 4 + 1]),
203		3 => println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}];",
204				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),
205		4 => println!("\t0x{:02x}, 0x{:02x}, 0x{:02x}, 0x{:02x}];",
206				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),
207		de => panic!("impossible value {}", de),
208	}
209}
210
211#[allow(dead_code)]
212fn print_u32_slice(arr :&[u32]) {
213	if arr.len() <= 4 {
214		for a in arr {
215			print!("0x{:02x} ", a);
216		}
217		println!("");
218		return;
219	}
220	println!("[");
221	let mut i :usize = 0;
222	while i * 4 < arr.len() - 4 {
223		println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x},",
224				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);
225		i += 1;
226	}
227	match arr.len() as i64 - i as i64 * 4 {
228		1 => println!("\t0x{:08x}];", arr[i * 4]),
229		2 => println!("\t0x{:08x}, 0x{:08x}];", arr[i * 4], arr[i * 4 + 1]),
230		3 => println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}];",
231				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),
232		4 => println!("\t0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}];",
233				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),
234		de => panic!("impossible value {}", de),
235	}
236}
237
238
239#[allow(dead_code)]
240fn print_f64_slice(arr :&[f64]) {
241	if arr.len() <= 4 {
242		for a in arr {
243			print!("0x{} ", a);
244		}
245		println!("");
246		return;
247	}
248	println!("[");
249	let mut i :usize = 0;
250	while i * 4 < arr.len() - 4 {
251		println!("\t{}, {}, {}, {},",
252				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]);
253		i += 1;
254	}
255	match arr.len() as i64 - i as i64 * 4 {
256		1 => println!("\t{}];", arr[i * 4]),
257		2 => println!("\t{}, {}];", arr[i * 4], arr[i * 4 + 1]),
258		3 => println!("\t{}, {}, {}];",
259				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2]),
260		4 => println!("\t{}, {}, {}, {}];",
261				arr[i * 4], arr[i * 4 + 1], arr[i * 4 + 2], arr[i * 4 + 3]),
262		de => panic!("impossible value {}", de),
263	}
264}