1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
//! In-memory backend, useful for testing.
use super::{AudioReader, AudioWriter};
use crate::buffer::{AudioBufferIn, AudioBufferOut, AudioChunk};

/// An [`AudioReader`] that reads from a given [`AudioChunk`].
/// The generic parameter type `S` represents the sample type.
///
/// [`AudioReader`]: ../trait.AudioReader.html
/// [`AudioChunk`]: ../../../buffer/struct.AudioChunk.html
pub struct AudioBufferReader<'b, S>
where
    S: Copy,
{
    frames_per_second: u64,
    frame: usize,
    buffer: &'b AudioChunk<S>,
}

impl<'b, S> AudioBufferReader<'b, S>
where
    S: Copy,
{
    /// Construct a new `AudioBufferReader` with the given [`AudioChunk`] and
    /// sample rate in frames per second.
    ///
    /// [`AudioChunk`]: ../../../buffer/struct.AudioChunk.html
    pub fn new(buffer: &'b AudioChunk<S>, frames_per_second: u64) -> Self {
        Self {
            buffer,
            frames_per_second,
            frame: 0,
        }
    }
}

impl<'b, S> AudioReader<S> for AudioBufferReader<'b, S>
where
    S: Copy,
{
    type Err = std::convert::Infallible;
    fn number_of_channels(&self) -> usize {
        self.buffer.channels().len()
    }
    fn frames_per_second(&self) -> u64 {
        self.frames_per_second
    }

    fn fill_buffer(&mut self, output: &mut AudioBufferOut<S>) -> Result<usize, Self::Err> {
        assert_eq!(output.number_of_channels(), self.number_of_channels());
        // Note: `self.number_of_channels() > 0`
        let buffer_size = output.number_of_frames();
        let remainder = self.buffer.channels()[0].len() - self.frame;
        let frames_to_copy = std::cmp::min(buffer_size, remainder);

        for (output_channel, input_channel) in
            output.channel_iter_mut().zip(self.buffer.channels().iter())
        {
            assert_eq!(buffer_size, output_channel.len());
            output_channel[0..frames_to_copy]
                .copy_from_slice(&input_channel[self.frame..self.frame + frames_to_copy]);
        }
        self.frame += frames_to_copy;
        Ok(frames_to_copy)
    }
}

#[cfg(test)]
mod AudioBufferReaderTests {
    mod fill_buffer {
        use super::super::super::AudioReader;
        use super::super::AudioBufferReader;
        use crate::buffer::{AudioBufferOut, AudioChunk};

        #[test]
        fn works_as_expected() {
            let audio_buffer =
                audio_chunk![[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]];
            let mut reader = AudioBufferReader::new(&audio_buffer, 16);
            let mut output_buffer = AudioChunk::zero(3, 2);
            let mut slices = output_buffer.as_mut_slices();
            {
                let mut buffers = AudioBufferOut::new(&mut slices, 2);
                assert_eq!(Ok(2), reader.fill_buffer(&mut buffers));
            }
            assert_eq!(slices[0], vec![1, 2].as_slice());
            assert_eq!(slices[1], vec![6, 7].as_slice());
            assert_eq!(slices[2], vec![11, 12].as_slice());
            {
                let mut buffers = AudioBufferOut::new(&mut slices, 2);
                assert_eq!(Ok(2), reader.fill_buffer(&mut buffers));
            }
            assert_eq!(slices[0], vec![3, 4].as_slice());
            assert_eq!(slices[1], vec![8, 9].as_slice());
            assert_eq!(slices[2], vec![13, 14].as_slice());
            {
                let mut buffers = AudioBufferOut::new(&mut slices, 2);
                assert_eq!(Ok(1), reader.fill_buffer(&mut buffers));
            }
            assert_eq!(slices[0], vec![5, 4].as_slice());
            assert_eq!(slices[1], vec![10, 9].as_slice());
            assert_eq!(slices[2], vec![15, 14].as_slice());
        }
    }
}

/// An [`AudioWriter`] that appends to a given [`AudioChunk`].
/// The generic parameter type `S` represents the sample type.
///
/// Note about using in a real-time context
/// =======================================
/// Because this appends to an [`AudioChunk`], it may allocate memory
/// when the capacity of the [`AudioChunk`] is exceeded.
///
/// [`AudioWriter`]: ../trait.AudioWriter.html
/// [`AudioChunk`]: ../../../buffer/struct.AudioChunk.html
pub struct AudioBufferWriter<'b, S> {
    buffer: &'b mut AudioChunk<S>,
}

impl<'b, S> AudioBufferWriter<'b, S> {
    pub fn new(buffer: &'b mut AudioChunk<S>) -> Self {
        Self { buffer }
    }
}

impl<'b, S> AudioWriter<S> for AudioBufferWriter<'b, S>
where
    S: Copy,
{
    type Err = std::convert::Infallible;
    fn write_buffer(&mut self, buffer: &AudioBufferIn<S>) -> Result<(), Self::Err> {
        self.buffer.append_sliced_chunk(buffer.channels());
        Ok(())
    }
}