1use std::{
2 fs::File,
3 io::{self, Read},
4};
5
6use super::{
7 format::{SampleParser, Signed16PCM},
8 stream_to_matrix, Matrix,
9};
10
11pub fn read_with_padding(file: &mut File, buffer: &mut [u8]) -> io::Result<()> {
15 let mut read_so_far = 0;
16
17 while read_so_far < buffer.len() {
18 let remaining_slice = &mut buffer[read_so_far..];
19
20 let n = file.read(remaining_slice)?;
21 if n > 0 {
22 read_so_far += n;
23 } else {
24 for b in remaining_slice {
27 *b = 0;
28 }
29
30 return Ok(());
31 }
32 }
33
34 Ok(())
35}
36
37pub struct FileSource {
38 file: File,
39 buffer: Vec<u8>,
40 channels: usize,
41 limit_rate: bool,
42 ms_sleep: u64,
43 }
45
46impl FileSource {
47 #[allow(clippy::new_ret_no_self)]
48 pub fn new(
49 path: &str,
50 opts: &crate::cfg::SourceOptions,
51 limit_rate: bool,
52 ) -> Result<Box<dyn super::DataSource<f64>>, std::io::Error> {
53 let samples_per_batch = (opts.buffer * opts.channels as u32) / 2;
54 let batches_per_second = opts.sample_rate / samples_per_batch;
55 let ms_sleep = (1000 / batches_per_second) as u64;
56 Ok(Box::new(FileSource {
57 channels: opts.channels,
58 limit_rate,
59 ms_sleep,
60 file: File::open(path)?,
61 buffer: vec![0u8; opts.buffer as usize * opts.channels],
62 }))
63 }
64}
65
66impl super::DataSource<f64> for FileSource {
67 fn recv(&mut self) -> Option<Matrix<f64>> {
68 if self.limit_rate {
69 std::thread::sleep(std::time::Duration::from_millis(self.ms_sleep));
70 }
71 match read_with_padding(&mut self.file, &mut self.buffer) {
72 Ok(()) => Some(stream_to_matrix(
73 self.buffer.chunks(2).map(Signed16PCM::parse),
74 self.channels,
75 32768.0,
76 )),
77 Err(_e) => None, }
79 }
80}