1 // Copyright (C) 2016  Lukas Lalinsky
2 // Distributed under the MIT license, see the LICENSE file for details.
3 
4 #ifndef CHROMAPRINT_AUDIO_AUDIO_SLICER_H_
5 #define CHROMAPRINT_AUDIO_AUDIO_SLICER_H_
6 
7 #include <cstddef>
8 #include <cstdint>
9 #include <cassert>
10 #include <vector>
11 #include "debug.h"
12 
13 namespace chromaprint {
14 
15 template <typename T>
16 class AudioSlicer {
17 public:
AudioSlicer(size_t size,size_t increment)18 	AudioSlicer(size_t size, size_t increment)
19 		: m_size(size), m_increment(increment), m_buffer(size * 2) {
20 		assert(size >= increment);
21 		Reset();
22 	}
23 
size()24 	size_t size() const {
25 		return m_size;
26 	}
27 
increment()28 	size_t increment() const {
29 		return m_increment;
30 	}
31 
Reset()32 	void Reset() {
33 		m_buffer_begin = m_buffer_end = m_buffer.begin();
34 	}
35 
36 	template <typename InputIt, typename ConsumerFunc>
Process(InputIt begin,InputIt end,ConsumerFunc consumer)37 	void Process(InputIt begin, InputIt end, ConsumerFunc consumer) {
38 		size_t size = std::distance(begin, end);
39 		size_t buffer_size = std::distance(m_buffer_begin, m_buffer_end);
40 
41 		while (buffer_size > 0 && buffer_size + size >= m_size) {
42 			consumer(&(*m_buffer_begin), &(*m_buffer_end), begin, std::next(begin, m_size - buffer_size));
43 			if (buffer_size >= m_increment) {
44 				std::advance(m_buffer_begin, m_increment);
45 				buffer_size -= m_increment;
46 				const size_t available_buffer_size = std::distance(m_buffer_end, m_buffer.end());
47 				if (buffer_size + available_buffer_size < m_size) {
48 					const auto new_buffer_begin = m_buffer.begin();
49 					m_buffer_end = std::copy(m_buffer_begin, m_buffer_end, new_buffer_begin);
50 					m_buffer_begin = new_buffer_begin;
51 				}
52 			} else {
53 				m_buffer_begin = m_buffer_end = m_buffer.begin();
54 				std::advance(begin, m_increment - buffer_size);
55 				size -= m_increment - buffer_size;
56 				buffer_size = 0;
57 			}
58 		}
59 
60 		if (buffer_size == 0) {
61 			while (size >= m_size) {
62 				consumer(begin, std::next(begin, m_size), end, end);
63 				std::advance(begin, m_increment);
64 				size -= m_increment;
65 			}
66 		}
67 
68 		assert(buffer_size + size < m_size);
69 		m_buffer_end = std::copy(begin, end, m_buffer_end);
70 	}
71 
72 private:
73 	size_t m_size;
74 	size_t m_increment;
75 	std::vector<T> m_buffer;
76 	typename std::vector<T>::iterator m_buffer_begin;
77 	typename std::vector<T>::iterator m_buffer_end;
78 };
79 
80 }; // namespace chromaprint
81 
82 #endif // CHROMAPRINT_AUDIO_AUDIO_SLICER_H_
83