1use super::arrayutils::find_sum_abs_f32;
19use super::arrayutils::is_constant;
20use super::arrayutils::SimdVec;
21use super::component::BitRepr;
22use super::component::BlockSizeSpec;
23use super::component::ChannelAssignment;
24use super::component::Constant;
25use super::component::FixedLpc;
26use super::component::Frame;
27use super::component::FrameHeader;
28use super::component::FrameOffset;
29use super::component::Lpc;
30use super::component::Residual;
31use super::component::SampleRateSpec;
32use super::component::SampleSizeSpec;
33use super::component::Stream;
34use super::component::StreamInfo;
35use super::component::SubFrame;
36use super::component::Verbatim;
37use super::config;
38use super::constant::fixed::MAX_LPC_ORDER as MAX_FIXED_LPC_ORDER;
39use super::constant::panic_msg;
40use super::constant::qlpc::MAX_ORDER as MAX_LPC_ORDER;
41use super::constant::MIN_BLOCK_SIZE_FOR_PREDICTION;
42use super::error::verify_range;
43use super::error::verify_true;
44use super::error::EncodeError;
45use super::error::Verified;
46use super::lpc;
47#[cfg(feature = "par")]
48use super::par;
49use super::rice;
50use super::source::Context;
51use super::source::FrameBuf;
52use super::source::Source;
53
54import_simd!(as simd);
55
56#[inline]
58const fn quotients_and_remainders(err: i32, rice_p: u8) -> (u32, u32) {
59 let remainder_mask = (1u32 << rice_p) - 1;
60 let err = rice::encode_signbit(err);
61 (err >> rice_p, err & remainder_mask)
62}
63
64#[inline]
66#[cfg(feature = "simd-nightly")]
67fn quotients_and_remainders_simd<const N: usize>(
68 err_v: simd::Simd<i32, N>,
69 rice_p: u8,
70 quotients: &mut [u32],
71 remainders: &mut [u32],
72) where
73 simd::LaneCount<N>: simd::SupportedLaneCount,
74{
75 let rice_p_v = simd::Simd::splat(u32::from(rice_p));
76 let remainder_mask_v = simd::Simd::splat((1u32 << rice_p) - 1);
77 let err_v = rice::encode_signbit_simd(err_v);
78 quotients.copy_from_slice((err_v >> rice_p_v).as_ref());
79 remainders.copy_from_slice((err_v & remainder_mask_v).as_ref());
80}
81
82#[cfg(feature = "simd-nightly")]
93#[inline]
94fn encode_residual_partition(
95 start: usize,
96 end: usize,
97 rice_p: u8,
98 errors: &[i32],
99 quotients: &mut [u32],
100 remainders: &mut [u32],
101) {
102 const SIMD_N: usize = 8;
103 let mut t = start;
105 let (head, body, tail) = errors[start..end].as_simd::<SIMD_N>();
106 for err in head {
107 (quotients[t], remainders[t]) = quotients_and_remainders(*err, rice_p);
108 t += 1;
109 }
110 for err_v in body {
111 quotients_and_remainders_simd::<SIMD_N>(
112 *err_v,
113 rice_p,
114 &mut quotients[t..t + SIMD_N],
115 &mut remainders[t..t + SIMD_N],
116 );
117 t += SIMD_N;
118 }
119 for err in tail {
120 (quotients[t], remainders[t]) = quotients_and_remainders(*err, rice_p);
121 t += 1;
122 }
123}
124
125#[cfg(not(feature = "simd-nightly"))]
127#[inline]
128fn encode_residual_partition(
129 start: usize,
130 end: usize,
131 rice_p: u8,
132 errors: &[i32],
133 quotients: &mut [u32],
134 remainders: &mut [u32],
135) {
136 let mut t = start;
137 for err in &errors[start..end] {
138 (quotients[t], remainders[t]) = quotients_and_remainders(*err, rice_p);
139 t += 1;
140 }
141}
142
143fn encode_residual_with_prc_parameter(
145 _config: &config::Prc,
146 errors: &[i32],
147 warmup_length: usize,
148 prc_p: rice::PrcParameter,
149) -> Residual {
150 let block_size = errors.len();
151 let nparts = 1 << prc_p.order;
152 let part_size = errors.len() >> prc_p.order;
153 debug_assert!(part_size >= warmup_length);
154
155 let mut quotients = vec![0u32; block_size];
156 let mut remainders = vec![0u32; block_size];
157
158 let mut offset = 0;
159 for rice_p in &prc_p.ps[0..nparts] {
160 let start = std::cmp::max(offset, warmup_length);
161 offset += part_size;
162 let end = offset;
163 encode_residual_partition(start, end, *rice_p, errors, &mut quotients, &mut remainders);
165 }
166 Residual::from_parts(
167 prc_p.order as u8,
168 block_size,
169 warmup_length,
170 prc_p.ps,
171 quotients,
172 remainders,
173 )
174}
175
176pub fn encode_residual(config: &config::Prc, errors: &[i32], warmup_length: usize) -> Residual {
178 let prc_p = rice::find_partitioned_rice_parameter(errors, warmup_length, config.max_parameter);
179 encode_residual_with_prc_parameter(config, errors, warmup_length, prc_p)
180}
181
182type FixedLpcErrors = [SimdVec<i32, 16>; MAX_FIXED_LPC_ORDER + 1];
183reusable!(FIXED_LPC_ERRORS: FixedLpcErrors);
184
185fn reset_fixed_lpc_errors(errors: &mut FixedLpcErrors, signal: &[i32]) {
187 errors[0].reset_from_slice(signal);
188
189 for order in 0..MAX_FIXED_LPC_ORDER {
190 let next_order = order + 1;
191
192 let mut carry = 0i32;
193 errors[next_order].resize(signal.len(), simd::Simd::default());
194 for t in 0..errors[order].simd_len() {
195 let x = errors[order].as_ref_simd()[t];
196 let mut shifted = x.rotate_elements_right::<1>();
197 (shifted[0], carry) = (carry, shifted[0]);
198 errors[next_order].as_mut_simd()[t] = x - shifted;
199 }
200 }
201}
202
203fn estimate_entropy(errors: &[i32], warmup_len: usize, partitions: usize) -> usize {
205 let block_size = errors.len();
213 let partition_size = (block_size + partitions - 1) / partitions;
214
215 let mut offset = 0;
216 let mut acc = 0;
217 for _p in 0..partitions {
218 let end = std::cmp::min(block_size, offset + partition_size);
219 let partition_len = end - offset;
220 if end >= warmup_len {
221 let sample_count = std::cmp::min(end - warmup_len, partition_len);
222 let sum_errors = find_sum_abs_f32::<16>(&errors[offset..end]);
223 let avg_errors = sum_errors * 2.0 / (sample_count as f32 + 0.00001);
224 let geom_p = 1.0 / (avg_errors + 1.0);
225 let xent = avg_errors.mul_add(-(1.0 - geom_p).log2(), -geom_p.log2());
226 acc += (xent * sample_count as f32) as usize;
227 }
228 offset = end;
229 }
230 acc
231}
232
233fn select_order_and_encode_residual<'a, I>(
235 order_sel: &config::OrderSel,
236 prc_config: &config::Prc,
237 errors: I,
238 bits_per_sample: usize,
239 baseline_bits: usize,
240) -> Option<(usize, Residual)>
241where
242 I: Iterator<Item = (usize, &'a [i32])>,
243{
244 let max_rice_p = prc_config.max_parameter;
245 match *order_sel {
246 config::OrderSel::BitCount => errors
247 .map(
248 #[inline]
249 |(order, err)| {
250 let prc_p = rice::find_partitioned_rice_parameter(err, order, max_rice_p);
251 let bits = bits_per_sample * order + prc_p.code_bits;
252 (order, err, prc_p, bits)
253 },
254 )
255 .min_by_key(|(_order, _err, _prc_p, bits)| *bits)
256 .and_then(
257 #[inline]
258 |(order, err, prc_p, bits)| {
259 (bits < baseline_bits).then(
260 #[inline]
261 || {
262 (
263 order,
264 encode_residual_with_prc_parameter(prc_config, err, order, prc_p),
265 )
266 },
267 )
268 },
269 ),
270 config::OrderSel::ApproxEnt { partitions } => errors
271 .map(
272 #[inline]
273 |(order, err)| {
274 (
275 order,
276 err,
277 estimate_entropy(err, order, partitions) + bits_per_sample * order,
278 )
279 },
280 )
281 .min_by_key(
282 #[inline]
283 |(_order, _err, bits)| *bits,
284 )
285 .and_then(
286 #[inline]
287 |(order, err, bits)| {
288 (bits < baseline_bits).then(|| (order, encode_residual(prc_config, err, order)))
289 },
290 ),
291 }
292}
293
294#[inline]
302fn fixed_lpc(
303 config: &config::SubFrameCoding,
304 signal: &[i32],
305 bits_per_sample: u8,
306 baseline_bits: usize,
307) -> Option<SubFrame> {
308 assert!(bits_per_sample < 30);
309 let max_order = config.fixed.max_order;
310
311 reuse!(FIXED_LPC_ERRORS, |errors: &mut FixedLpcErrors| {
312 reset_fixed_lpc_errors(errors, signal);
313 let errors = errors
314 .iter()
315 .map(SimdVec::as_ref)
316 .take(max_order + 1)
317 .enumerate();
318 select_order_and_encode_residual(
319 &config.fixed.order_sel,
320 &config.prc,
321 errors,
322 bits_per_sample as usize,
323 baseline_bits,
324 )
325 .map(|(order, residual)| {
326 FixedLpc::from_parts(
327 heapless::Vec::from_slice(&signal[..order])
328 .expect("Exceeded maximum order for FixedLpc component."),
329 residual,
330 bits_per_sample,
331 )
332 .into()
333 })
334 })
335}
336
337fn perform_qlpc(
338 config: &config::SubFrameCoding,
339 signal: &[i32],
340) -> heapless::Vec<f64, MAX_LPC_ORDER> {
341 if config.qlpc.use_direct_mse {
342 if config.qlpc.mae_optimization_steps > 0 {
343 lpc::lpc_with_irls_mae(
344 signal,
345 &config.qlpc.window,
346 config.qlpc.lpc_order,
347 config.qlpc.mae_optimization_steps,
348 )
349 } else {
350 lpc::lpc_with_direct_mse(signal, &config.qlpc.window, config.qlpc.lpc_order)
351 }
352 } else {
353 lpc::lpc_from_autocorr(signal, &config.qlpc.window, config.qlpc.lpc_order)
354 }
355}
356
357reusable!(QLPC_ERROR_BUFFER: Vec<i32>);
358
359fn estimated_qlpc(
365 config: &config::SubFrameCoding,
366 signal: &[i32],
367 bits_per_sample: u8,
368) -> SubFrame {
369 let lpc_order = config.qlpc.lpc_order;
370 let lpc_coefs = perform_qlpc(config, signal);
371 let qlpc = lpc::quantize_parameters(&lpc_coefs[0..lpc_order], config.qlpc.quant_precision);
372 let residual = reuse!(QLPC_ERROR_BUFFER, |errors: &mut Vec<i32>| {
373 errors.resize(signal.len(), 0i32);
374 lpc::compute_error(&qlpc, signal, errors);
375 encode_residual(&config.prc, errors, qlpc.order())
376 });
377 Lpc::from_parts(
378 heapless::Vec::from_slice(&signal[0..qlpc.order()])
379 .expect("LPC order exceeded the maximum"),
380 qlpc,
381 residual,
382 bits_per_sample,
383 )
384 .into()
385}
386
387fn encode_subframe(
389 config: &config::SubFrameCoding,
390 samples: &[i32],
391 bits_per_sample: u8,
392) -> SubFrame {
393 if config.use_constant && is_constant(samples) {
394 Constant::from_parts(samples.len(), samples[0], bits_per_sample).into()
396 } else {
397 let baseline_bits =
398 Verbatim::count_bits_from_metadata(samples.len(), bits_per_sample as usize);
399
400 let too_short = samples.len() < MIN_BLOCK_SIZE_FOR_PREDICTION;
401 let fixed = if !too_short && config.use_fixed {
402 fixed_lpc(config, samples, bits_per_sample, baseline_bits)
403 } else {
404 None
405 };
406
407 let baseline_bits = fixed.as_ref().map_or(baseline_bits, |x| {
408 std::cmp::min(baseline_bits, x.count_bits())
409 });
410 let est_lpc = if !too_short && config.use_lpc {
411 let candidate = estimated_qlpc(config, samples, bits_per_sample);
412 (candidate.count_bits() < baseline_bits).then_some(candidate)
413 } else {
414 None
415 };
416
417 est_lpc
418 .or(fixed)
419 .unwrap_or_else(|| Verbatim::from_samples(samples, bits_per_sample).into())
420 }
421}
422
423fn encode_frame_impl(
425 config: &config::Encoder,
426 framebuf: &FrameBuf,
427 offset: u64,
428 stream_info: &StreamInfo,
429 ch_info: &ChannelAssignment,
430) -> Frame {
431 let nchannels = stream_info.channels();
432 let bits_per_sample = stream_info.bits_per_sample();
433 let mut frame = Frame::new_empty(
434 BlockSizeSpec::from_size(framebuf.filled_size() as u16),
435 ch_info.clone(),
436 SampleSizeSpec::from_bits(bits_per_sample as u8).unwrap_or(SampleSizeSpec::Unspecified),
437 SampleRateSpec::from_freq(stream_info.sample_rate() as u32)
438 .unwrap_or(SampleRateSpec::Unspecified),
439 );
440 frame
441 .header_mut()
442 .set_frame_offset(FrameOffset::StartSample(offset));
443 for ch in 0..nchannels {
444 frame.add_subframe(encode_subframe(
445 &config.subframe_coding,
446 framebuf.channel_slice(ch),
447 (bits_per_sample + ch_info.bits_per_sample_offset(ch)) as u8,
448 ));
449 }
450
451 frame
452}
453
454#[allow(clippy::tuple_array_conversions)] #[inline]
457fn recombine_stereo_frame(header: FrameHeader, indep: Frame, ms: Frame) -> Frame {
458 let (_header, l, r) = indep
459 .into_stereo_channels()
460 .expect(panic_msg::DATA_INCONSISTENT);
461 let (_header, m, s) = ms
462 .into_stereo_channels()
463 .expect(panic_msg::DATA_INCONSISTENT);
464
465 let chans = header.channel_assignment().select_channels(l, r, m, s);
466 Frame::from_parts(header, vec![chans.0, chans.1])
467}
468
469reusable!(MSFRAMEBUF: FrameBuf = FrameBuf::new_stereo_buffer());
470
471fn try_stereo_coding(
473 config: &config::Encoder,
474 framebuf: &FrameBuf,
475 indep: Frame,
476 offset: u64,
477 stream_info: &StreamInfo,
478) -> Frame {
479 reuse!(MSFRAMEBUF, |ms_framebuf: &mut FrameBuf| {
480 ms_framebuf.resize(framebuf.size());
481 ms_framebuf.fill_stereo_with_iter(
482 framebuf
483 .channel_slice(0)
484 .iter()
485 .zip(framebuf.channel_slice(1).iter())
486 .map(|(l, r)| ((l + r) >> 1, l - r)),
487 );
488 let ms_frame = encode_frame_impl(
489 config,
490 ms_framebuf,
491 offset,
492 stream_info,
493 &ChannelAssignment::MidSide,
494 );
495
496 let (bits_l, bits_r, bits_m, bits_s) = (
497 indep.subframe(0).unwrap().count_bits(),
498 indep.subframe(1).unwrap().count_bits(),
499 ms_frame.subframe(0).unwrap().count_bits(),
500 ms_frame.subframe(1).unwrap().count_bits(),
501 );
502
503 let combinations = [
504 config
505 .stereo_coding
506 .use_leftside
507 .then_some((ChannelAssignment::LeftSide, bits_l + bits_s)),
508 config
509 .stereo_coding
510 .use_rightside
511 .then_some((ChannelAssignment::RightSide, bits_r + bits_s)),
512 config
513 .stereo_coding
514 .use_midside
515 .then_some((ChannelAssignment::MidSide, bits_m + bits_s)),
516 ];
517
518 let mut min_bits = bits_l + bits_r;
519 let mut min_ch_info = ChannelAssignment::Independent(2);
520 for (ch_info, bits) in combinations.iter().flatten() {
521 if *bits < min_bits {
522 min_bits = *bits;
523 min_ch_info = ch_info.clone();
524 }
525 }
526 let mut header = ms_frame.header().clone();
527 header.reset_channel_assignment(min_ch_info);
528 recombine_stereo_frame(header, indep, ms_frame)
529 })
530}
531
532fn encode_frame(
534 config: &config::Encoder,
535 framebuf: &FrameBuf,
536 offset: u64,
537 stream_info: &StreamInfo,
538) -> Frame {
539 let nchannels = stream_info.channels();
540 let ch_info = ChannelAssignment::Independent(nchannels as u8);
541 let mut ret = encode_frame_impl(config, framebuf, offset, stream_info, &ch_info);
542
543 if nchannels == 2 {
544 ret = try_stereo_coding(config, framebuf, ret, offset, stream_info);
545 }
546 ret
547}
548
549pub fn encode_fixed_size_frame(
585 config: &Verified<config::Encoder>,
586 framebuf: &FrameBuf,
587 frame_number: usize,
588 stream_info: &StreamInfo,
589) -> Result<Frame, EncodeError> {
590 verify_range!(
591 "encode_fixed_size_frame (frame_number)",
592 frame_number,
593 ..(1usize << 31)
594 )?;
595
596 framebuf.verify_samples(stream_info.bits_per_sample())?;
597 let mut ret = encode_frame(config, framebuf, 0, stream_info);
606 ret.header_mut()
607 .set_frame_offset(FrameOffset::Frame(frame_number as u32));
608 Ok(ret)
609}
610
611pub fn encode_with_fixed_block_size<T: Source>(
649 config: &Verified<config::Encoder>,
650 mut src: T,
651 block_size: usize,
652) -> Result<Stream, EncodeError> {
653 #[cfg(feature = "par")]
654 {
655 if config.multithread {
656 return par::encode_with_fixed_block_size(config, src, block_size);
657 }
658 }
659 let mut stream = Stream::new(src.sample_rate(), src.channels(), src.bits_per_sample())?;
660 let mut framebuf_and_context = (
661 FrameBuf::with_size(src.channels(), block_size)?,
662 Context::new(src.bits_per_sample(), src.channels()),
663 );
664
665 stream
669 .stream_info_mut()
670 .set_block_sizes(block_size, block_size)
671 .unwrap();
672
673 loop {
674 let read_samples = src.read_samples(block_size, &mut framebuf_and_context)?;
675 if read_samples == 0 {
676 break;
677 }
678 let frame = encode_fixed_size_frame(
679 config,
680 &framebuf_and_context.0,
681 framebuf_and_context.1.current_frame_number().unwrap(),
682 stream.stream_info(),
683 )?;
684 stream.add_frame(frame);
685 }
686
687 let (_, context) = framebuf_and_context;
688 stream
689 .stream_info_mut()
690 .set_md5_digest(&context.md5_digest());
691 stream
692 .stream_info_mut()
693 .set_total_samples(src.len_hint().unwrap_or_else(|| context.total_samples()));
694 Ok(stream)
695}
696
697#[cfg(test)]
698mod tests {
699 use super::*;
700 use crate::component::Decode;
701 use crate::error::Verify;
702 use crate::sigen;
703 use crate::sigen::Signal;
704 use crate::source;
705 use crate::source::Fill;
706
707 #[test]
708 fn fixed_lpc_error_computation() {
709 let mut errors = FixedLpcErrors::default();
710 let signal = sigen::Sine::new(32, 0.3)
711 .noise(0.1)
712 .to_vec_quantized(16, 64);
713 reset_fixed_lpc_errors(&mut errors, &signal);
714 let unpacked = errors[1].as_ref();
715 for t in 1..signal.len() {
716 assert_eq!(unpacked[t], signal[t] - signal[t - 1]);
717 }
718 let unpacked = errors[2].as_ref();
719 for t in 2..signal.len() {
720 assert_eq!(unpacked[t], signal[t] - 2 * signal[t - 1] + signal[t - 2]);
721 }
722 }
723
724 #[test]
725 fn fixed_lpc_of_sine() {
726 let signal = sigen::Sine::new(100, 0.6).to_vec_quantized(8, 1024);
727 let mut config = config::SubFrameCoding::default();
728 for order in 0..=MAX_FIXED_LPC_ORDER {
729 config.fixed.max_order = order;
730 let subframe = fixed_lpc(&config, &signal, 8, usize::MAX)
731 .expect("Should return Some because `baseline_bits` is usize::MAX.");
732 subframe.verify().expect("Should return valid subframe.");
733 assert_eq!(subframe.decode(), signal);
734 }
735 }
736
737 #[test]
738 fn md5_invariance() {
739 let channels = 2;
740 let bits_per_sample = 24;
741 let sample_rate = 16000;
742 let block_size = 128;
743 let constant: f32 = (23f64 / f64::from(1 << 23)) as f32;
744 let signal_len = 1024;
745 let signal =
746 sigen::Dc::new(constant).to_vec_quantized(bits_per_sample, signal_len * channels);
747 assert_eq!(signal[0], 23);
748 let source =
749 source::MemSource::from_samples(&signal, channels, bits_per_sample, sample_rate);
750 let stream = encode_with_fixed_block_size(
751 &config::Encoder::default().into_verified().unwrap(),
752 source,
753 block_size,
754 )
755 .expect("Source read error");
756 eprintln!("MD5 of DC signal ({constant}) with len={signal_len} and ch={channels} was",);
757 eprint!("[");
758 for &b in stream.stream_info().md5_digest() {
759 eprint!("0x{b:02X}, ");
760 }
761 eprintln!("]");
762 assert_eq!(
763 stream.stream_info().md5_digest(),
764 &[
765 0xEE, 0x78, 0x7A, 0x6E, 0x99, 0x01, 0x36, 0x79, 0xA5, 0xBB, 0x6D, 0x5C, 0x10, 0xAF,
766 0x0B, 0x87
767 ]
768 );
769 }
770
771 #[test]
772 fn losslessness_residual_coding() {
773 let signal = sigen::Noise::new(0.4).to_vec_quantized(8, 64);
774 let residual = encode_residual(&config::Prc::default(), &signal, 0);
775 let decoded = residual.decode();
776 assert_eq!(decoded, signal);
777
778 let signal = sigen::Noise::new(0.9)
779 .concat(2048, sigen::Sine::new(40, 0.1))
780 .to_vec_quantized(8, 4096);
781 let residual = encode_residual(&config::Prc::default(), &signal, 0);
782 let decoded = residual.decode();
783 assert_eq!(decoded, signal);
784 }
785
786 #[test]
787 fn losslessness_subframe_coding() {
788 let bits_per_sample = 8;
789 let config = config::SubFrameCoding::default();
790 let signal = sigen::Noise::new(0.4).to_vec_quantized(bits_per_sample, 64);
791 let subframe = encode_subframe(&config, &signal, bits_per_sample as u8);
792 let decoded = subframe.decode();
793 assert_eq!(decoded, signal);
794
795 let signal = sigen::Sine::new(40, 0.9).to_vec_quantized(bits_per_sample, 64);
796 let subframe = encode_subframe(&config, &signal, bits_per_sample as u8);
797 let decoded = subframe.decode();
798 assert_eq!(decoded, signal);
799 }
800
801 #[test]
802 fn encoding_zeros() {
803 let channel_count = 1;
804 let block_size = 64;
805 let bits_per_sample = 8;
806 let sample_rate = 88200;
807 let stream_info = StreamInfo::new(sample_rate, channel_count, bits_per_sample).unwrap();
808 let mut fb = FrameBuf::with_size(channel_count, block_size).unwrap();
809 fb.fill_interleaved(&vec![0; block_size]).unwrap();
810 let frame = encode_fixed_size_frame(
811 &config::Encoder::default().into_verified().unwrap(),
812 &fb,
813 0,
814 &stream_info,
815 )
816 .unwrap();
817 frame.verify().unwrap();
818
819 assert_eq!(frame.decode(), vec![0; block_size]);
820 }
821
822 #[test]
823 fn order_selector_bitcount() {
824 let block_size = 256;
825 let bits_per_sample = 16;
826 let prc_config = config::Prc::default();
827 let errors = [
828 vec![255i32; block_size],
829 vec![256i32; block_size],
830 vec![128i32; block_size],
831 ];
832 let select_result = select_order_and_encode_residual(
833 &config::OrderSel::BitCount,
834 &prc_config,
835 errors.iter().map(AsRef::as_ref).enumerate(),
836 bits_per_sample,
837 usize::MAX,
838 );
839 let (selected_order, residual) =
840 select_result.expect("should be `Some` because baseline_bits == usize::MAX.");
841 residual.verify().expect("should return a valid residual.");
842
843 assert_eq!(selected_order, 0);
844 let selected_count = residual.count_bits() + selected_order * bits_per_sample;
845
846 for (order, err) in errors.iter().enumerate() {
847 let ref_residual = encode_residual(&prc_config, err, order);
848 let ref_count = ref_residual.count_bits() + bits_per_sample * order;
849 assert!(
850 ref_count >= selected_count,
851 "should select the error sequence that minimizes the bit count."
852 );
853 if order == selected_order {
854 assert!(ref_residual.decode() == residual.decode());
855 }
856 }
857 }
858
859 #[test]
860 fn order_selector_approxent() {
861 let block_size = 256;
862 let bits_per_sample = 16;
863 let prc_config = config::Prc::default();
864 let errors = [
865 vec![255i32; block_size],
866 vec![256i32; block_size],
867 vec![128i32; block_size],
868 vec![127i32; block_size],
869 ];
870 let select_result = select_order_and_encode_residual(
871 &config::OrderSel::ApproxEnt { partitions: 32 },
872 &prc_config,
873 errors.iter().map(AsRef::as_ref).enumerate(),
874 bits_per_sample,
875 usize::MAX,
876 );
877 let (selected_order, residual) =
878 select_result.expect("should be `Some` because baseline_bits == usize::MAX.");
879 residual.verify().expect("should return a valid residual.");
880
881 assert_eq!(selected_order, 2);
882 }
883
884 }
918
919#[cfg(all(test, feature = "simd-nightly"))]
920mod bench {
921 use super::*;
922 use crate::source::Fill;
923
924 extern crate test;
925
926 use test::bench::Bencher;
927 use test::black_box;
928
929 use crate::error::Verify;
930 use crate::sigen;
931 use crate::sigen::Signal;
932
933 #[bench]
934 fn residual_encoder_zero(b: &mut Bencher) {
935 let errors = [0i32; 4096];
936 let cfg = &config::Prc::default();
937 b.iter(|| encode_residual(black_box(cfg), black_box(&errors), black_box(3)));
938 }
939
940 #[bench]
941 fn residual_partition_encoder_zero(b: &mut Bencher) {
942 let errors = [0i32; 4096];
943 let mut quotients = [0u32; 4096];
944 let mut remainders = [0u32; 4096];
945 b.iter(|| {
946 encode_residual_partition(
947 black_box(1024),
948 black_box(2048),
949 black_box(10u8),
950 black_box(&errors),
951 black_box(&mut quotients),
952 black_box(&mut remainders),
953 );
954 (quotients, remainders)
955 });
956 }
957
958 #[bench]
959 fn fixed_lpc_encoding_zero(b: &mut Bencher) {
960 let signal = [0i32; 4096];
961 let cfg = &config::SubFrameCoding::default();
962 b.iter(|| {
963 fixed_lpc(
964 black_box(cfg),
965 black_box(&signal),
966 black_box(16u8),
967 black_box(0usize),
968 )
969 });
970 }
971
972 #[bench]
973 fn fixed_size_frame_encoder_zero(b: &mut Bencher) {
974 let cfg = &config::Encoder::default().into_verified().unwrap();
975 let stream_info = StreamInfo::new(44100, 2, 16).unwrap();
976 let mut fb = FrameBuf::with_size(2, 4096).unwrap();
977 #[allow(clippy::large_stack_arrays)] fb.fill_interleaved(&[0i32; 4096 * 2]).unwrap();
980 b.iter(|| {
981 encode_fixed_size_frame(
982 black_box(cfg),
983 black_box(&fb),
984 black_box(123usize),
985 &stream_info,
986 )
987 });
988 }
989
990 fn bench_stereo_frame_encoder_impl<S: Signal>(
991 b: &mut Bencher,
992 signal: &S,
993 use_constant: bool,
994 use_fixed: bool,
995 use_lpc: bool,
996 ) {
997 let mut cfg = config::Encoder::default();
998 cfg.subframe_coding.use_constant = use_constant;
999 cfg.subframe_coding.use_fixed = use_fixed;
1000 cfg.subframe_coding.use_lpc = use_lpc;
1001 let cfg = cfg.into_verified().unwrap();
1002 let stream_info = StreamInfo::new(48000, 2, 16).unwrap();
1003 let mut fb = FrameBuf::with_size(2, 4096).unwrap();
1004 let signal = signal.to_vec_quantized(16, 4096 * 2);
1005 fb.fill_interleaved(&signal).unwrap();
1006 b.iter(|| {
1007 encode_fixed_size_frame(
1008 black_box(&cfg),
1009 black_box(&fb),
1010 black_box(123usize),
1011 &stream_info,
1012 )
1013 });
1014 }
1015
1016 #[bench]
1017 fn stereo_frame_encoder_pure_sine_fixed(b: &mut Bencher) {
1018 bench_stereo_frame_encoder_impl(b, &sigen::Sine::new(200, 0.4), false, true, false);
1019 }
1020
1021 #[bench]
1022 fn stereo_frame_encoder_pure_sine_lpc(b: &mut Bencher) {
1023 bench_stereo_frame_encoder_impl(b, &sigen::Sine::new(200, 0.4), false, false, true);
1024 }
1025
1026 #[bench]
1027 fn stereo_frame_encoder_noisy_sine_fixed(b: &mut Bencher) {
1028 bench_stereo_frame_encoder_impl(
1029 b,
1030 &sigen::Sine::new(200, 0.4).noise(0.4),
1031 false,
1032 true,
1033 false,
1034 );
1035 }
1036
1037 #[bench]
1038 fn stereo_frame_encoder_noisy_sine_lpc(b: &mut Bencher) {
1039 bench_stereo_frame_encoder_impl(
1040 b,
1041 &sigen::Sine::new(200, 0.4).noise(0.4),
1042 false,
1043 false,
1044 true,
1045 );
1046 }
1047
1048 #[bench]
1049 fn normal_qlpc_noise(b: &mut Bencher) {
1050 let cfg = &config::SubFrameCoding::default();
1051 let bits_per_sample = 16u8;
1052 let signal = sigen::Noise::new(0.6).to_vec_quantized(bits_per_sample as usize, 4096);
1053
1054 b.iter(|| {
1055 estimated_qlpc(
1056 black_box(cfg),
1057 black_box(&signal),
1058 black_box(bits_per_sample),
1059 )
1060 });
1061 }
1062}