Entropy Piano Tuner  1.1.3 (documentation not yet complete)
An open-source experimental software for piano tuning by entropy minimization
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
circularbuffer.h
Go to the documentation of this file.
1 /*****************************************************************************
2  * Copyright 2015 Haye Hinrichsen, Christoph Wick
3  *
4  * This file is part of Entropy Piano Tuner.
5  *
6  * Entropy Piano Tuner is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * Entropy Piano Tuner is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * Entropy Piano Tuner. If not, see http://www.gnu.org/licenses/.
18  *****************************************************************************/
19 
20 //=============================================================================
21 // Circular buffer
22 //=============================================================================
23 
24 #ifndef CIRCULAR_BUFFER
25 #define CIRCULAR_BUFFER
26 
27 #include <vector>
28 #include <assert.h>
29 #include <cstring>
30 #include <algorithm>
31 
33 
49 
50 template <class data_type>
52 {
53 public:
54  CircularBuffer(std::size_t maximum_size = 0);
55 
56  void clear();
57  void push_back(const data_type &data);
58  void resize(std::size_t maximum_size);
59  std::vector<data_type> getOrderedData() const;
60  std::vector<data_type> readData(size_t n);
61  std::size_t size() const {return mCurrentSize;}
62  std::size_t maximum_size() const
63  {return mMaximumSize;}
64 
65 private:
66  std::size_t mCurrentWritePosition;
67  std::size_t mCurrentReadPosition;
68  std::size_t mMaximumSize;
69  std::size_t mCurrentSize;
70  std::vector<data_type> mData;
71 };
72 
73 
74 
75 //=============================================================================
76 // Circular buffer implementation (contained in header because of template)
77 //=============================================================================
78 
79 //-----------------------------------------------------------------------------
80 // Constructor
81 //-----------------------------------------------------------------------------
82 
86 
87 template <class data_type>
89  : mCurrentWritePosition(0),
90  mCurrentReadPosition(0),
91  mMaximumSize(maximum_size),
92  mCurrentSize(0),
93  mData()
94 {
95  mData.resize(mMaximumSize);
96 }
97 
98 
99 //-----------------------------------------------------------------------------
100 // Clear the buffer, keeping its maximal size
101 //-----------------------------------------------------------------------------
102 
107 
108 template <class data_type>
110 {
111  mCurrentWritePosition = 0;
112  mCurrentReadPosition = 0;
113  mCurrentSize = 0;
114 }
115 
116 
117 //-----------------------------------------------------------------------------
118 // Append a new data element
119 //-----------------------------------------------------------------------------
120 
126 
127 template <class data_type>
128 void CircularBuffer<data_type>::push_back(const data_type &data)
129 {
130  assert(mMaximumSize > 0);
131  assert(mCurrentWritePosition < mMaximumSize);
132  assert(mCurrentReadPosition < mMaximumSize);
133  // write at the desired position
134  mData[mCurrentWritePosition] = data;
135  // update write pointer
136  mCurrentWritePosition = (mCurrentWritePosition+1) % mMaximumSize;
137  // update current size
138  mCurrentSize = std::min(mCurrentSize + 1, mMaximumSize);
139  // update read pointer (add mMaximumSize to keep it positive)
140  mCurrentReadPosition = (mCurrentWritePosition + mMaximumSize - mCurrentSize) % mMaximumSize;
141 }
142 
143 
144 //-----------------------------------------------------------------------------
145 // Copy data in an ordered form
146 //-----------------------------------------------------------------------------
147 
157 
158 template <class data_type>
159 std::vector<data_type> CircularBuffer<data_type>::getOrderedData() const
160 {
161  std::vector<data_type> data_out(mCurrentSize);
162  // copy end
163  std::size_t part1Size = std::min(mCurrentReadPosition + mCurrentSize, mMaximumSize) - mCurrentReadPosition;
164  std::memcpy(data_out.data(), mData.data() + mCurrentReadPosition, part1Size * sizeof(data_type));
165 
166  // copy start
167  std::size_t part2Size = mCurrentSize - part1Size;
168  std::memcpy(data_out.data() + part1Size, mData.data(), part2Size * sizeof(data_type));
169 
170  return data_out;
171 }
172 
173 
174 
175 //-----------------------------------------------------------------------------
176 // Retrieve time-ordeded data with max size of n and remove if from the buffer
177 //-----------------------------------------------------------------------------
178 
184 
185 template <class data_type>
186 std::vector<data_type> CircularBuffer<data_type>::readData(size_t n)
187 {
188  std::vector<data_type> data_out(std::move(getOrderedData()));
189  if (data_out.size() > n) data_out.resize(n);
190 
191  EptAssert(mCurrentSize >= data_out.size(), "Do not read more data than existent.");
192 
193  // reset read position
194  mCurrentReadPosition = (mCurrentReadPosition + data_out.size()) % mMaximumSize;
195  mCurrentSize = mCurrentSize - data_out.size();
196 
197  return data_out;
198 }
199 
200 
201 //-----------------------------------------------------------------------------
202 // Resize the buffer
203 //-----------------------------------------------------------------------------
204 
211 
212 template <class data_type>
213 void CircularBuffer<data_type>::resize(std::size_t maximum_size)
214 {
215  // we have to temporarily store the old data and rewrite at at position 0
216  std::vector<data_type> old_data(std::move(getOrderedData()));
217  mMaximumSize = maximum_size;
218  // new current size is size of old data, or smaller)
219  mCurrentSize = std::min(old_data.size(), maximum_size);
220  // resize or internal data structure
221  mData.resize(mMaximumSize);
222 
223  // dont copy data if new buffer is empty
224  if (mMaximumSize == 0) return;
225 
226  // reset read and write pointers
227  mCurrentReadPosition = 0;
228  mCurrentWritePosition = mCurrentSize % mMaximumSize;
229  // copy the old data
230  std::memcpy(mData.data(),
231  old_data.data() + (old_data.size() - mCurrentSize),
232  mCurrentSize * sizeof(data_type));
233 }
234 
235 
236 #endif // CIRCULAR_BUFFER
std::size_t maximum_size() const
Return actual maximal size.
std::size_t mMaximumSize
Maximal size of the buffer.
std::vector< data_type > getOrderedData() const
Copy entire data in a time-ordered form.
std::size_t mCurrentSize
Current size of the buffer.
std::size_t mCurrentWritePosition
Current read position.
std::vector< data_type > mData
Internal cyclic data buffer.
CircularBuffer(std::size_t maximum_size=0)
Construct an empty buffer of maximal size zero.
std::vector< data_type > readData(size_t n)
Retrieve time-ordeded data with maximum size of n and remove if from the buffer.
Template class for a circular buffer.
void resize(std::size_t maximum_size)
Resize the buffer, shrink oldest data if necessary.
std::size_t size() const
Return current buffer size.
void push_back(const data_type &data)
Append a new data element to the buffer.
std::size_t mCurrentReadPosition
Current write position.
#define EptAssert(a, b)
Definition: eptexception.h:47
void clear()
Clear the buffer, keeping its maximal size.