Audio Processing Framework (APF) version 0.5.0
blockdelayline.h
Go to the documentation of this file.
1/******************************************************************************
2 Copyright (c) 2012-2016 Institut für Nachrichtentechnik, Universität Rostock
3 Copyright (c) 2006-2012 Quality & Usability Lab
4 Deutsche Telekom Laboratories, TU Berlin
5
6 Permission is hereby granted, free of charge, to any person obtaining a copy
7 of this software and associated documentation files (the "Software"), to deal
8 in the Software without restriction, including without limitation the rights
9 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 copies of the Software, and to permit persons to whom the Software is
11 furnished to do so, subject to the following conditions:
12
13 The above copyright notice and this permission notice shall be included in
14 all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 THE SOFTWARE.
23*******************************************************************************/
24
25// https://AudioProcessingFramework.github.io/
26
29
30#ifndef APF_BLOCKDELAYLINE_H
31#define APF_BLOCKDELAYLINE_H
32
33#include <algorithm> // for std::max()
34#include <vector> // default container
35
36#include "apf/iterator.h" // for circular_iterator, stride_iterator
37
38namespace apf
39{
40
46template<typename T, typename Container = std::vector<T>>
48{
49 public:
50 using size_type = typename Container::size_type;
51 using difference_type = typename Container::difference_type;
52 using pointer = typename Container::pointer;
54
55 BlockDelayLine(size_type block_size, size_type max_delay);
56
62 bool delay_is_valid(size_type delay, size_type& corrected) const
63 {
64 bool valid = (delay <= _max_delay);
65 corrected = valid ? delay : _max_delay;
66 return valid;
67 }
68
70 bool delay_is_valid(size_type delay) const
71 {
72 size_type dummy; // dummy variable as default parameter
73 return delay_is_valid(delay, dummy);
74 }
75
77 void advance()
78 {
79 ++_block_circulator;
80 _data_circulator += static_cast<difference_type>(_block_size);
81 }
82
83 template<typename Iterator>
84 void write_block(Iterator source);
85
86 template<typename Iterator>
87 bool read_block(Iterator destination, size_type delay) const;
88
89 template<typename Iterator>
90 bool read_block(Iterator destination, size_type delay, T weight) const;
91
92 pointer get_write_pointer() const;
93
94 circulator get_read_circulator(size_type delay = 0) const;
95
96 protected:
98 circulator _get_data_circulator() const { return _data_circulator; }
99
100 const size_type _block_size;
101
102 private:
103 const size_type _max_delay;
104
105 const size_type _number_of_blocks;
106
107 Container _data;
108
110 circulator _data_circulator;
111
113 apf::stride_iterator<circulator> _block_circulator;
114};
115
120template<typename T, typename Container>
122 , size_type max_delay)
123 : _block_size(block_size)
124 , _max_delay(max_delay)
125 // Minimum number of blocks is 2, even if _max_delay is 0.
126 // With only one block the circular iterators r and (r + _block_size) would be
127 // equal and the read...() functions wouldn't work.
128 // But anyway, who wants a delay line with no delay? Kind of useless ...
129 , _number_of_blocks(
130 std::max(size_type(2), (_max_delay + 2 * _block_size - 1) / _block_size))
131 , _data(_number_of_blocks * _block_size) // initialized with default ctor T()
132 , _data_circulator(_data.begin(), _data.end())
133 , _block_circulator(
134 _data_circulator, static_cast<difference_type>(_block_size))
135{
136 assert(_block_size >= 1);
137}
138
149template<typename T, typename Container>
150template<typename Iterator>
151void
153{
154 this->advance();
155 // Ignore return value, next time get_write_pointer() has to be used again!
156 std::copy(source, source + _block_size, this->get_write_pointer());
157}
158
164template<typename T, typename Container>
165template<typename Iterator>
166bool
167BlockDelayLine<T, Container>::read_block(Iterator destination, size_type delay)
168 const
169{
170 // TODO: try to get a more meaningful error message if source is not a random
171 // access iterator (e.g. when using a std::list)
172 if (!this->delay_is_valid(delay)) return false;
173 circulator source = this->get_read_circulator(delay);
174 std::copy(source, source + static_cast<difference_type>(_block_size)
175 , destination);
176 return true;
177}
178
180template<typename T, typename Container>
181template<typename Iterator>
182bool
184 , size_type delay, T weight) const
185{
186 if (!this->delay_is_valid(delay)) return false;
187 circulator source = this->get_read_circulator(delay);
188 std::transform(source, source + static_cast<difference_type>(_block_size)
189 , destination, [weight] (T in) { return in * weight; });
190 return true;
191}
192
199template<typename T, typename Container>
200typename BlockDelayLine<T, Container>::pointer
202{
203 return &*_block_circulator.base().base();
204}
205
211template<typename T, typename Container>
214{
215 return _get_data_circulator() - static_cast<difference_type>(delay);
216}
217
223template<typename T, typename Container = std::vector<T>>
224class NonCausalBlockDelayLine : private BlockDelayLine<T, Container>
225{
226 private:
228
229 public:
230 using typename _base::size_type;
231 using typename _base::circulator;
232 using difference_type = typename _base::circulator::difference_type;
233
239 NonCausalBlockDelayLine(size_type block_size, size_type max_delay
240 , size_type initial_delay)
241 : _base(block_size, max_delay + initial_delay)
242 , _initial_delay(static_cast<difference_type>(initial_delay))
243 {}
244
245#ifdef APF_DOXYGEN_HACK
246 // This is just for Doxygen documentation:
248 void advance();
250 template<typename Iterator> void write_block(Iterator source);
252 pointer get_write_pointer() const;
253#else
254 // This is the real thing:
255 using _base::advance;
256 using _base::write_block;
258#endif
259
266 bool delay_is_valid(difference_type delay, difference_type& corrected) const
267 {
268 if (delay < -_initial_delay)
269 {
270 corrected = -_initial_delay;
271 return false;
272 }
273 size_type tmp;
274 bool valid = _base::delay_is_valid(
275 static_cast<size_type>(delay + _initial_delay), tmp);
276 corrected = static_cast<difference_type>(tmp) - _initial_delay;
277 return valid;
278 }
279
281 bool delay_is_valid(difference_type delay) const
282 {
283 difference_type dummy; // dummy variable as default parameter
284 return delay_is_valid(delay, dummy);
285 }
286
288 template<typename Iterator>
289 bool read_block(Iterator destination, difference_type delay) const
290 {
291 if (delay < -_initial_delay) return false;
292 return _base::read_block(destination
293 , static_cast<size_type>(delay + _initial_delay));
294 }
295
297 template<typename Iterator>
298 bool read_block(Iterator destination, difference_type delay, T weight) const
299 {
300 if (delay < -_initial_delay) return false;
301 return _base::read_block(destination
302 , static_cast<size_type>(delay + _initial_delay), weight);
303 }
304
306 circulator get_read_circulator(difference_type delay = 0) const
307 {
308 return _base::get_read_circulator(delay + _initial_delay);
309 }
310
311 private:
312 const difference_type _initial_delay;
313};
314
315} // namespace apf
316
317#endif
Block-based delay line.
pointer get_write_pointer() const
Get the write pointer.
void advance()
Advance the internal iterators/pointers to the next block.
const size_type _block_size
Size of read/write blocks.
bool delay_is_valid(size_type delay, size_type &corrected) const
Check if a given delay is valid.
BlockDelayLine(size_type block_size, size_type max_delay)
Constructor.
bool delay_is_valid(size_type delay) const
Return true if delay is valid.
circulator get_read_circulator(size_type delay=0) const
Get the read circulator.
bool read_block(Iterator destination, size_type delay) const
Read a block of data from the delay line.
void write_block(Iterator source)
Write a block of data to the delay line.
circulator _get_data_circulator() const
Get a circular iterator to the sample with time 0.
bool read_block(Iterator destination, size_type delay, T weight) const
Read from the delay line and multiply each element by a given factor.
A block-based delay line where negative delay is possible.
void write_block(Iterator source)
NonCausalBlockDelayLine(size_type block_size, size_type max_delay, size_type initial_delay)
Constructor.
circulator get_read_circulator(difference_type delay=0) const
bool read_block(Iterator destination, difference_type delay) const
bool read_block(Iterator destination, difference_type delay, T weight) const
bool delay_is_valid(difference_type delay, difference_type &corrected) const
Check if a given delay is valid.
bool delay_is_valid(difference_type delay) const
Return true if delay is valid.
pointer get_write_pointer() const
A stride iterator.
Definition: iterator.h:1051
Several more or less useful iterators and some macros.
Audio Processing Framework.
Definition: iterator.h:61