1use std::fmt;
18
19use md5::Digest;
20
21use super::arrayutils::deinterleave;
22use super::arrayutils::find_min_and_max;
23use super::arrayutils::le_bytes_to_i32s;
24use super::constant::MAX_BLOCK_SIZE;
25use super::constant::MAX_CHANNELS;
26use super::constant::MIN_BLOCK_SIZE;
27use super::error::verify_range;
28use super::error::verify_true;
29use super::error::SourceError;
30use super::error::VerifyError;
31
32pub trait Fill {
42 fn fill_interleaved(&mut self, interleaved: &[i32]) -> Result<(), SourceError>;
59
60 fn fill_le_bytes(&mut self, bytes: &[u8], bytes_per_sample: usize) -> Result<(), SourceError>;
81}
82
83impl<T: Fill, U: Fill> Fill for (T, U) {
84 fn fill_interleaved(&mut self, interleaved: &[i32]) -> Result<(), SourceError> {
85 self.0.fill_interleaved(interleaved)?;
86 self.1.fill_interleaved(interleaved)
87 }
88
89 fn fill_le_bytes(&mut self, bytes: &[u8], bytes_per_sample: usize) -> Result<(), SourceError> {
90 self.0.fill_le_bytes(bytes, bytes_per_sample)?;
91 self.1.fill_le_bytes(bytes, bytes_per_sample)
92 }
93}
94
95impl<'a, T> Fill for &'a mut T
96where
97 T: Fill,
98{
99 fn fill_interleaved(&mut self, interleaved: &[i32]) -> Result<(), SourceError> {
100 T::fill_interleaved(self, interleaved)
101 }
102
103 fn fill_le_bytes(&mut self, bytes: &[u8], bytes_per_sample: usize) -> Result<(), SourceError> {
104 T::fill_le_bytes(self, bytes, bytes_per_sample)
105 }
106}
107
108#[derive(Clone, Debug)]
110pub struct FrameBuf {
111 samples: Vec<i32>,
112 channels: usize,
113 size: usize,
114 readbuf: Vec<i32>, }
116
117impl FrameBuf {
118 pub(crate) fn new_stereo_buffer() -> Self {
124 Self {
125 samples: vec![0i32; 256 * 2],
126 channels: 2,
127 size: 256,
128 readbuf: vec![],
129 }
130 }
131
132 pub fn with_size(channels: usize, size: usize) -> Result<Self, VerifyError> {
147 verify_range!("FrameBuf::with_size (channels)", channels, 1..=MAX_CHANNELS)?;
148 verify_range!(
149 "FrameBuf::with_size (block size)",
150 size,
151 MIN_BLOCK_SIZE..=MAX_BLOCK_SIZE
152 )?;
153 Ok(Self {
154 samples: vec![0i32; size * channels],
155 channels,
156 size,
157 readbuf: vec![],
158 })
159 }
160
161 pub const fn size(&self) -> usize {
171 self.size
172 }
173
174 pub fn resize(&mut self, new_size: usize) {
186 self.size = new_size;
187 self.samples.resize(self.size * self.channels, 0i32);
188 }
189
190 pub const fn channels(&self) -> usize {
200 self.channels
201 }
202
203 pub(crate) fn channel_slice(&self, ch: usize) -> &[i32] {
205 &self.samples[ch * self.size..(ch + 1) * self.size]
206 }
207
208 pub(crate) fn channel_slice_mut(&mut self, ch: usize) -> &mut [i32] {
210 &mut self.samples[ch * self.size..(ch + 1) * self.size]
211 }
212
213 #[cfg(test)]
215 pub(crate) fn raw_slice(&self) -> &[i32] {
216 &self.samples
217 }
218
219 pub(crate) fn verify_samples(&self, bits_per_sample: usize) -> Result<(), VerifyError> {
221 let max_allowed = (1i32 << (bits_per_sample - 1)) - 1;
222 let min_allowed = -(1i32 << (bits_per_sample - 1));
223 for ch in 0..self.channels() {
224 let (min, max) = find_min_and_max::<64>(self.channel_slice(ch), 0i32);
225 if min < min_allowed || max > max_allowed {
226 return Err(VerifyError::new(
227 "input.framebuf",
228 &format!("input sample must be in the range of bits={bits_per_sample}"),
229 ));
230 }
231 }
232 Ok(())
233 }
234}
235
236impl Fill for FrameBuf {
237 fn fill_interleaved(&mut self, interleaved: &[i32]) -> Result<(), SourceError> {
238 let stride = self.size();
239 deinterleave(interleaved, self.channels, stride, &mut self.samples);
240 Ok(())
241 }
242
243 fn fill_le_bytes(&mut self, bytes: &[u8], bytes_per_sample: usize) -> Result<(), SourceError> {
244 self.readbuf.resize(bytes.len() / bytes_per_sample, 0);
245 le_bytes_to_i32s(bytes, &mut self.readbuf, bytes_per_sample);
246
247 let stride = self.size();
248 deinterleave(&self.readbuf, self.channels, stride, &mut self.samples);
249 Ok(())
250 }
251}
252
253#[derive(Clone)]
259pub struct Context {
260 md5: md5::Md5,
261 bytes_per_sample: usize,
262 channels: usize,
263 sample_count: usize,
264 frame_count: usize,
265 current_block_size: usize,
266}
267
268impl Context {
269 pub fn new(bits_per_sample: usize, channels: usize, block_size: usize) -> Self {
284 let bytes_per_sample = (bits_per_sample + 7) / 8;
285 assert!(
286 bytes_per_sample <= 4,
287 "bits_per_sample={bits_per_sample} cannot be larger than 32."
288 );
289 Self {
290 md5: md5::Md5::new(),
291 bytes_per_sample,
292 channels,
293 sample_count: 0,
294 frame_count: 0,
295 current_block_size: block_size,
296 }
297 }
298
299 #[inline]
301 pub fn bytes_per_sample(&self) -> usize {
302 self.bytes_per_sample
303 }
304
305 #[allow(dead_code)]
310 pub(crate) fn set_current_block_size(&mut self, size: usize) {
311 self.current_block_size = size;
312 }
313
314 #[inline]
327 #[allow(clippy::unnecessary_lazy_evaluations)] pub fn current_frame_number(&self) -> Option<usize> {
329 (self.frame_count > 0).then(|| self.frame_count - 1)
330 }
331
332 #[inline]
348 pub fn md5_digest(&self) -> [u8; 16] {
349 self.md5.clone().finalize().into()
350 }
351
352 #[inline]
364 pub fn total_samples(&self) -> usize {
365 self.sample_count
366 }
367}
368
369const ZEROS: [u8; 2048] = [0u8; 2048];
370
371impl Fill for Context {
372 fn fill_interleaved(&mut self, interleaved: &[i32]) -> Result<(), SourceError> {
373 if interleaved.is_empty() {
374 return Ok(());
375 }
376 for v in interleaved {
377 self.md5.update(&v.to_le_bytes()[0..self.bytes_per_sample]);
378 }
379 let remain_samples = self.current_block_size * self.channels - interleaved.len();
380 let mut remain = remain_samples * self.bytes_per_sample;
381 while remain > 0 {
382 let bytes = std::cmp::min(ZEROS.len(), remain);
383 let slice = &ZEROS[0..bytes];
384 self.md5.update(slice);
385 remain -= bytes;
386 }
387 self.sample_count += interleaved.len() / self.channels;
388 self.frame_count += 1;
389 Ok(())
390 }
391
392 fn fill_le_bytes(&mut self, bytes: &[u8], bytes_per_sample: usize) -> Result<(), SourceError> {
393 if bytes.is_empty() {
394 return Ok(());
395 }
396 self.md5.update(bytes);
397 let block_byte_count = self.current_block_size * self.channels * bytes_per_sample;
398 let mut remain = block_byte_count - bytes.len();
399 while remain > 0 {
400 let bytes = std::cmp::min(ZEROS.len(), remain);
401 let slice = &ZEROS[0..bytes];
402 self.md5.update(slice);
403 remain -= bytes;
404 }
405 self.sample_count += bytes.len() / self.channels / bytes_per_sample;
406 self.frame_count += 1;
407 Ok(())
408 }
409}
410
411impl fmt::Debug for Context {
412 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
413 let digest = format!("{:?}", self.md5.clone().finalize());
414 f.debug_struct("Context")
415 .field("bytes_per_sample", &self.bytes_per_sample)
416 .field("channels", &self.channels)
417 .field("sample_count", &self.sample_count)
418 .field("frame_count", &self.frame_count)
419 .field("md5", &digest)
420 .field("current_block_size", &self.current_block_size)
421 .finish()
422 }
423}
424
425pub trait Source {
427 fn channels(&self) -> usize;
429 fn bits_per_sample(&self) -> usize;
431 fn sample_rate(&self) -> usize;
433 fn read_samples<F: Fill>(
444 &mut self,
445 block_size: usize,
446 dest: &mut F,
447 ) -> Result<usize, SourceError>;
448 fn len_hint(&self) -> Option<usize> {
450 None
451 }
452}
453
454impl<'a, T: Source> Source for &'a mut T {
455 fn channels(&self) -> usize {
456 T::channels(self)
457 }
458 fn bits_per_sample(&self) -> usize {
459 T::bits_per_sample(self)
460 }
461 fn sample_rate(&self) -> usize {
462 T::sample_rate(self)
463 }
464 fn read_samples<F: Fill>(
465 &mut self,
466 block_size: usize,
467 dest: &mut F,
468 ) -> Result<usize, SourceError> {
469 T::read_samples(self, block_size, dest)
470 }
471 fn len_hint(&self) -> Option<usize> {
472 T::len_hint(self)
473 }
474}
475
476pub trait Seekable: Source {
481 fn is_empty(&self) -> bool {
483 self.len() == 0
484 }
485
486 fn len(&self) -> usize;
488
489 fn read_samples_from<F: Fill>(
495 &mut self,
496 offset: usize,
497 block_size: usize,
498 context: &mut F,
499 ) -> Result<usize, SourceError>;
500}
501
502impl<'a, T: Seekable> Seekable for &'a mut T {
503 fn is_empty(&self) -> bool {
504 T::is_empty(self)
505 }
506
507 fn len(&self) -> usize {
508 T::len(self)
509 }
510
511 fn read_samples_from<F: Fill>(
512 &mut self,
513 offset: usize,
514 block_size: usize,
515 context: &mut F,
516 ) -> Result<usize, SourceError> {
517 T::read_samples_from(self, offset, block_size, context)
518 }
519}
520
521#[derive(Clone, Debug)]
523#[allow(clippy::module_name_repetitions)]
524pub struct MemSource {
525 channels: usize,
526 bits_per_sample: usize,
527 sample_rate: usize,
528 samples: Vec<i32>,
529 read_head: usize,
530}
531
532impl MemSource {
533 pub fn from_samples(
544 samples: &[i32],
545 channels: usize,
546 bits_per_sample: usize,
547 sample_rate: usize,
548 ) -> Self {
549 Self {
550 channels,
551 bits_per_sample,
552 sample_rate,
553 samples: samples.to_owned(),
554 read_head: 0,
555 }
556 }
557
558 pub fn as_slice(&self) -> &[i32] {
568 &self.samples
569 }
570}
571
572impl Source for MemSource {
573 fn channels(&self) -> usize {
574 self.channels
575 }
576
577 fn bits_per_sample(&self) -> usize {
578 self.bits_per_sample
579 }
580
581 fn sample_rate(&self) -> usize {
582 self.sample_rate
583 }
584
585 fn read_samples<F: Fill>(
586 &mut self,
587 block_size: usize,
588 dest: &mut F,
589 ) -> Result<usize, SourceError> {
590 self.read_samples_from(self.read_head, block_size, dest)
591 }
592
593 fn len_hint(&self) -> Option<usize> {
594 Some(self.len())
595 }
596}
597
598impl Seekable for MemSource {
599 fn len(&self) -> usize {
600 self.samples.len() / self.channels()
601 }
602
603 fn read_samples_from<F: Fill>(
604 &mut self,
605 offset: usize,
606 block_size: usize,
607 dest: &mut F,
608 ) -> Result<usize, SourceError> {
609 let to_read = block_size * self.channels;
610 let begin = std::cmp::min(offset * self.channels, self.samples.len());
611 let end = std::cmp::min(offset * self.channels + to_read, self.samples.len());
612 let src = &self.samples[begin..end];
613
614 dest.fill_interleaved(src)?;
615
616 let read_samples = (end - begin) / self.channels;
617 self.read_head += read_samples;
618 Ok(read_samples)
619 }
620}
621
622#[cfg(test)]
623#[allow(clippy::pedantic, clippy::nursery, clippy::needless_range_loop)]
624mod tests {
625 use super::*;
626
627 #[test]
628 fn reading_and_deinterleaving() {
629 let mut signal = vec![];
630 let block_size = 512;
631 let channels = 4;
632 for t in 0..block_size {
633 for _ch in 0..channels {
634 signal.push(t as i32);
635 }
636 }
637
638 let mut src = MemSource::from_samples(&signal, channels, 16, 16000);
639 let mut framebuf_and_ctx = (
640 FrameBuf::with_size(channels, block_size).unwrap(),
641 Context::new(16, channels, block_size),
642 );
643 let read = src
644 .read_samples_from(0, block_size, &mut framebuf_and_ctx)
645 .expect("Read error");
646 assert_eq!(read, block_size);
647 let (framebuf, _ctx) = framebuf_and_ctx;
648 let mut head = 0;
649 for _ch in 0..channels {
650 for t in 0..block_size {
651 assert_eq!(framebuf.raw_slice()[head], t as i32);
652 head += 1;
653 }
654 }
655 }
656
657 #[test]
658 fn sequential_read() {
659 let mut signal = vec![];
660 let total_size = 1100;
661 let channels = 3;
662 for t in 0..total_size {
663 for ch in 0..channels {
664 let sign: i32 = if ch == 0 { 1 } else { -1 };
665 signal.push(sign * t);
666 }
667 }
668
669 let block_size = 128;
670 let mut src = MemSource::from_samples(&signal, channels, 16, 16000);
671 let ctx = Context::new(16, channels, block_size);
672 let framebuf = FrameBuf::with_size(channels, block_size).unwrap();
673 let mut framebuf_and_ctx = (framebuf, ctx);
674
675 for step in 0..8 {
676 let read = src
677 .read_samples(block_size, &mut framebuf_and_ctx)
678 .expect("Read error");
679 assert_eq!(read, 128);
680 assert_eq!(src.read_head, 128 * (step + 1));
681 for t in 0..block_size {
682 assert_eq!(
683 framebuf_and_ctx.0.channel_slice(0)[t],
684 (block_size * step + t) as i32
685 );
686 assert_eq!(
687 framebuf_and_ctx.0.channel_slice(1)[t],
688 -((block_size * step + t) as i32)
689 );
690 }
691 }
692 let read = src
693 .read_samples(block_size, &mut framebuf_and_ctx)
694 .expect("Read error");
695 assert_eq!(read, 76);
696 for t in 0..76 {
697 assert_eq!(framebuf_and_ctx.0.channel_slice(0)[t], (1024 + t) as i32);
698 assert_eq!(framebuf_and_ctx.0.channel_slice(1)[t], -((1024 + t) as i32));
699 assert_eq!(framebuf_and_ctx.0.channel_slice(2)[t], -((1024 + t) as i32));
700 }
701 }
702
703 #[test]
704 fn md5_computation() {
705 let mut ctx = Context::new(16, 2, 32);
706 ctx.fill_interleaved(&[0i32; 32 * 2])
707 .expect("update failed");
708
709 assert_eq!(
711 ctx.md5_digest(),
712 [
713 0xF0, 0x9F, 0x35, 0xA5, 0x63, 0x78, 0x39, 0x45, 0x8E, 0x46, 0x2E, 0x63, 0x50, 0xEC,
714 0xBC, 0xE4
715 ]
716 );
717
718 let mut ctx = Context::new(16, 2, 32);
719 ctx.fill_interleaved(&[0xABCDi32; 32 * 2])
720 .expect("update failed");
721 assert_eq!(
723 ctx.md5_digest(),
724 [
725 0x02, 0x3D, 0x3A, 0xE9, 0x26, 0x0B, 0xB0, 0xC9, 0x51, 0xF6, 0x5B, 0x25, 0x24, 0x62,
726 0xB1, 0xFA
727 ]
728 );
729 }
730}
731
732#[cfg(all(test, feature = "simd-nightly"))]
733mod bench {
734 use super::*;
735
736 extern crate test;
737
738 use test::bench::Bencher;
739 use test::black_box;
740
741 #[bench]
742 fn feeding_bytes_to_context(b: &mut Bencher) {
743 let (bytes_per_sample, channels, block_size) = (2, 2, 4096);
744 let mut ctx = Context::new(bytes_per_sample, channels, block_size);
745 let signal_bytes = vec![0u8; bytes_per_sample * channels * block_size];
746 b.iter(|| ctx.fill_le_bytes(black_box(&signal_bytes), bytes_per_sample));
747 }
748}