1#![doc = include_str!("../README.md")]
17#![cfg_attr(feature = "simd-nightly", feature(portable_simd))]
18#![cfg_attr(feature = "simd-nightly", feature(test))]
19#![warn(clippy::all, clippy::nursery, clippy::pedantic, clippy::cargo)]
21#![allow(unknown_lints)]
22#![allow(
25 clippy::cast_possible_truncation,
26 clippy::cast_possible_wrap,
27 clippy::cast_precision_loss,
28 clippy::cast_sign_loss,
29 clippy::missing_const_for_fn,
30 clippy::multiple_crate_versions,
31 clippy::must_use_candidate,
32 clippy::wildcard_dependencies,
33 clippy::manual_is_multiple_of )]
35#![warn(
37 clippy::clone_on_ref_ptr,
38 clippy::create_dir,
39 clippy::dbg_macro,
40 clippy::empty_structs_with_brackets,
41 clippy::exit,
42 clippy::if_then_some_else_none,
43 clippy::impl_trait_in_params,
44 clippy::implicit_clone,
45 clippy::let_underscore_must_use,
46 clippy::lossy_float_literal,
47 clippy::multiple_inherent_impl,
48 clippy::print_stdout,
49 clippy::rc_buffer,
50 clippy::rc_mutex,
51 clippy::rest_pat_in_fully_bound_structs,
52 clippy::separated_literal_suffix,
53 clippy::str_to_string,
54 clippy::string_add,
55 clippy::try_err,
56 clippy::unnecessary_self_imports,
57 clippy::wildcard_enum_match_arm
58)]
59#![allow(clippy::needless_raw_string_hashes, clippy::doc_markdown)]
61#![allow(clippy::non_std_lazy_statics)]
63
64macro_rules! import_simd {
66 (as $modalias:ident) => {
67 #[cfg(feature = "simd-nightly")]
68 use std::simd as $modalias;
69 #[cfg(not(feature = "simd-nightly"))]
70 use $crate::fakesimd as $modalias;
71
72 #[allow(unused_imports)]
73 use simd::prelude::*;
74
75 #[allow(unused_imports)]
76 use simd::StdFloat;
77 };
78}
79
80macro_rules! reusable {
93 ($key:ident: $t:ty) => {
94 thread_local! {
95 static $key: std::cell::RefCell<$t> = std::cell::RefCell::new(Default::default());
96 }
97 };
98 ($key:ident: $t:ty = $init:expr) => {
99 thread_local! {
100 static $key: std::cell::RefCell<$t> = std::cell::RefCell::new($init);
101 }
102 };
103}
104
105macro_rules! reuse {
112 ($key:ident, $fn:expr) => {{
113 #[allow(clippy::redundant_closure_call)]
114 $key.with(|cell| $fn(&mut cell.borrow_mut()))
115 }};
116}
117
118#[allow(unused)]
120macro_rules! info { (target: $t:literal, $($x:tt)*) => (
121 #[cfg(feature = "log")] {
122 log::info!(target: $t, $($x)*)
123 }
124) }
125
126pub(crate) mod arrayutils;
127pub mod bitsink;
128pub(crate) mod coding;
129pub mod component;
130pub mod config;
131pub mod constant;
132pub mod error;
133#[cfg(not(feature = "simd-nightly"))]
134#[doc(hidden)]
135pub(crate) mod fakesimd;
136pub(crate) mod lpc;
137#[cfg(feature = "par")]
138pub(crate) mod par;
139pub(crate) mod repeat;
140pub(crate) mod rice;
141#[cfg(any(test, feature = "__export_sigen"))]
142#[doc(hidden)]
143pub mod sigen;
144pub mod source;
145
146#[cfg(test)]
147pub mod test_helper;
148
149#[cfg(clippy)]
151mod doctest_helper;
152
153#[cfg(feature = "mimalloc")]
154use mimalloc::MiMalloc;
155#[cfg(feature = "mimalloc")]
156#[global_allocator]
157static GLOBAL: MiMalloc = MiMalloc;
158
159pub use coding::encode_fixed_size_frame;
161
162pub use coding::encode_with_fixed_block_size;
163
164#[cfg(test)]
165mod tests {
166 #[cfg(feature = "serde")]
168 use super::error::Verify;
169 #[cfg(feature = "serde")]
170 use super::*;
171 #[cfg(feature = "serde")]
172 use crate::sigen::Signal;
173 #[cfg(feature = "serde")]
174 use rstest::rstest;
175
176 #[allow(dead_code)] const FIXED_BLOCK_CONFIGS: [&str; 5] = [
178 "",
179 r"
180block_sizes = [512]
181 ",
182 r"
183block_sizes = [123]
184 ",
185 r"
186block_sizes = [1024]
187[subframe_coding.qlpc]
188use_direct_mse = true
189mae_optimization_steps = 2
190 ",
191 r"
192multithread = false
193 ",
194 ];
195
196 #[cfg(feature = "serde")]
202 #[rstest]
203 fn e2e_with_generated_sinusoids(
204 #[values(1, 2, 3, 5, 8)] channels: usize,
205 #[values(16000, 16001, 95800)] sample_rate: usize,
206 #[values(FIXED_BLOCK_CONFIGS[0],
207 FIXED_BLOCK_CONFIGS[1],
208 FIXED_BLOCK_CONFIGS[2],
209 FIXED_BLOCK_CONFIGS[3],
210 FIXED_BLOCK_CONFIGS[4])]
211 config: &str,
212 ) {
213 let signal_len = 16123;
214 let bits_per_sample = 16;
215
216 let mut channel_signals = vec![];
217 for _ch in 0..channels {
218 channel_signals.push(
219 sigen::Sine::new(36, 0.4)
220 .noise(0.04)
221 .to_vec_quantized(bits_per_sample, signal_len),
222 );
223 }
224
225 let mut signal = vec![];
226 for t in 0..signal_len {
227 for s in &channel_signals {
228 signal.push(s[t]);
229 }
230 }
231 let mut config: config::Encoder = toml::from_str(config).expect("config parsing error");
232
233 if !cfg!(feature = "experimental") {
234 config.subframe_coding.qlpc.use_direct_mse = false;
236 config.subframe_coding.qlpc.mae_optimization_steps = 0;
237 }
238
239 let config = config.into_verified().expect("config value error");
240
241 let source =
242 source::MemSource::from_samples(&signal, channels, bits_per_sample, sample_rate);
243
244 test_helper::integrity_test(
245 |s| {
246 coding::encode_with_fixed_block_size(&config, s, config.block_size)
247 .expect("source error")
248 },
249 &source,
250 );
251 }
252
253 reusable!(REUSABLE_BUF: Vec<i32>);
254
255 #[test]
256 fn call_twice() {
257 fn fn1() {
258 reuse!(REUSABLE_BUF, |buf: &mut Vec<i32>| {
259 assert_eq!(buf.len(), 0);
260 buf.resize(5, 0i32);
261 });
262 }
263
264 fn fn2() {
265 reuse!(REUSABLE_BUF, |buf: &mut Vec<i32>| {
266 assert_eq!(buf.len(), 5);
267 });
268 }
269
270 fn1();
271 fn2();
272 }
273}