1 | /* |
2 | Copyright 2018 Google Inc. All Rights Reserved. |
3 | |
4 | Licensed under the Apache License, Version 2.0 (the "License"); |
5 | you may not use this file except in compliance with the License. |
6 | You may obtain a copy of the License at |
7 | |
8 | http://www.apache.org/licenses/LICENSE-2.0 |
9 | |
10 | Unless required by applicable law or agreed to in writing, software |
11 | distributed under the License is distributed on an "AS-IS" BASIS, |
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | See the License for the specific language governing permissions and |
14 | limitations under the License. |
15 | */ |
16 | |
17 | #include "dsp/circular_buffer.h" |
18 | |
19 | #include <algorithm> |
20 | |
21 | #include "base/constants_and_types.h" |
22 | |
23 | namespace vraudio { |
24 | |
25 | CircularBuffer::CircularBuffer(size_t buffer_length, size_t num_input_frames, |
26 | size_t num_output_frames) |
27 | : num_input_frames_(num_input_frames), |
28 | num_output_frames_(num_output_frames), |
29 | buffer_(kNumMonoChannels, buffer_length), |
30 | write_cursor_(0), |
31 | read_cursor_(0), |
32 | num_valid_frames_(0) { |
33 | CHECK_GE(buffer_length, num_input_frames + num_output_frames); |
34 | } |
35 | |
36 | bool CircularBuffer::InsertBuffer(const AudioBuffer::Channel& input) { |
37 | DCHECK_EQ(input.size(), num_input_frames_); |
38 | |
39 | if (num_valid_frames_ + num_input_frames_ > buffer_.num_frames()) { |
40 | return false; |
41 | } |
42 | // Remaining space after the write cursor. |
43 | const size_t forward_write_space = read_cursor_ <= write_cursor_ |
44 | ? buffer_.num_frames() - write_cursor_ |
45 | : read_cursor_ - write_cursor_; |
46 | |
47 | // Copy the input into the buffer. |
48 | AudioBuffer::Channel* buffer_channel = &buffer_[0]; |
49 | if (forward_write_space >= num_input_frames_) { |
50 | DCHECK_LE(buffer_channel->begin() + write_cursor_ + num_input_frames_, |
51 | buffer_channel->end()); |
52 | std::copy(first: input.begin(), last: input.end(), |
53 | result: buffer_channel->begin() + write_cursor_); |
54 | } else { |
55 | DCHECK_LE(buffer_channel->begin() + write_cursor_ + forward_write_space, |
56 | buffer_channel->end()); |
57 | DCHECK_LT(input.begin() + forward_write_space, input.end()); |
58 | std::copy(first: input.begin(), last: input.begin() + forward_write_space, |
59 | result: buffer_channel->begin() + write_cursor_); |
60 | DCHECK_LE(buffer_channel->begin() + forward_write_space, |
61 | buffer_channel->end()); |
62 | std::copy(first: input.begin() + forward_write_space, last: input.end(), |
63 | result: buffer_channel->begin()); |
64 | } |
65 | |
66 | write_cursor_ = (write_cursor_ + num_input_frames_) % buffer_.num_frames(); |
67 | num_valid_frames_ += num_input_frames_; |
68 | return true; |
69 | } |
70 | |
71 | bool CircularBuffer::RetrieveBuffer(AudioBuffer::Channel* output) { |
72 | return RetrieveBufferWithOffset(/*offset=*/0, output); |
73 | } |
74 | |
75 | bool CircularBuffer::RetrieveBufferWithOffset(size_t offset, |
76 | AudioBuffer::Channel* output) { |
77 | DCHECK_LE(output->begin() + num_output_frames_ + offset, output->end()); |
78 | |
79 | if (num_valid_frames_ < num_output_frames_) { |
80 | return false; |
81 | } |
82 | // Remaining space after the read cursor. |
83 | const size_t forward_read_space = read_cursor_ < write_cursor_ |
84 | ? write_cursor_ - read_cursor_ |
85 | : buffer_.num_frames() - read_cursor_; |
86 | |
87 | // Copy the buffer values into the output. |
88 | AudioBuffer::Channel* buffer_channel = &buffer_[0]; |
89 | if (forward_read_space >= num_output_frames_) { |
90 | DCHECK_LE(buffer_channel->begin() + read_cursor_ + num_output_frames_, |
91 | buffer_channel->end()); |
92 | std::copy(first: buffer_channel->begin() + read_cursor_, |
93 | last: buffer_channel->begin() + read_cursor_ + num_output_frames_, |
94 | result: output->begin() + offset); |
95 | } else { |
96 | DCHECK_LE(buffer_channel->begin() + read_cursor_ + forward_read_space, |
97 | buffer_channel->end()); |
98 | DCHECK_LE(output->begin() + forward_read_space + offset, output->end()); |
99 | std::copy(first: buffer_channel->begin() + read_cursor_, |
100 | last: buffer_channel->begin() + read_cursor_ + forward_read_space, |
101 | result: output->begin() + offset); |
102 | DCHECK_GE(buffer_channel->begin() + num_output_frames_ - forward_read_space, |
103 | buffer_channel->begin()); |
104 | DCHECK_LE(output->begin() + offset + num_output_frames_, output->end()); |
105 | std::copy(first: buffer_channel->begin(), |
106 | last: buffer_channel->begin() + num_output_frames_ - forward_read_space, |
107 | result: output->begin() + offset + forward_read_space); |
108 | } |
109 | read_cursor_ = (read_cursor_ + num_output_frames_) % buffer_.num_frames(); |
110 | num_valid_frames_ -= num_output_frames_; |
111 | return true; |
112 | } |
113 | |
114 | void CircularBuffer::Clear() { |
115 | read_cursor_ = 0; |
116 | write_cursor_ = 0; |
117 | num_valid_frames_ = 0; |
118 | } |
119 | |
120 | } // namespace vraudio |
121 | |