Chris@0
|
1 /* -*- c-basic-offset: 4 -*- vi:set ts=8 sts=4 sw=4: */
|
Chris@0
|
2
|
Chris@0
|
3 /*
|
Chris@0
|
4 A waveform viewer and audio annotation editor.
|
Chris@2
|
5 Chris Cannam, Queen Mary University of London, 2005-2006
|
Chris@0
|
6
|
Chris@0
|
7 This is experimental software. Not for distribution.
|
Chris@0
|
8 */
|
Chris@0
|
9
|
Chris@0
|
10 /*
|
Chris@0
|
11 This is a modified version of a source file from the
|
Chris@0
|
12 Rosegarden MIDI and audio sequencer and notation editor.
|
Chris@0
|
13 This file copyright 2000-2005 Chris Cannam.
|
Chris@0
|
14 */
|
Chris@0
|
15
|
Chris@0
|
16 #ifndef _RINGBUFFER_H_
|
Chris@0
|
17 #define _RINGBUFFER_H_
|
Chris@0
|
18
|
Chris@0
|
19 #include <sys/types.h>
|
Chris@0
|
20
|
Chris@0
|
21 #include "System.h"
|
Chris@0
|
22 #include "Scavenger.h"
|
Chris@0
|
23
|
Chris@0
|
24 //#define DEBUG_RINGBUFFER 1
|
Chris@0
|
25
|
Chris@0
|
26 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
27 #include <iostream>
|
Chris@0
|
28 #endif
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * RingBuffer implements a lock-free ring buffer for one writer and N
|
Chris@0
|
32 * readers, that is to be used to store a sample type T.
|
Chris@0
|
33 *
|
Chris@0
|
34 * For efficiency, RingBuffer frequently initialises samples by
|
Chris@0
|
35 * writing zeroes into their memory space, so T should normally be a
|
Chris@0
|
36 * simple type that can safely be set to zero using memset.
|
Chris@0
|
37 */
|
Chris@0
|
38
|
Chris@0
|
39 template <typename T, int N = 1>
|
Chris@0
|
40 class RingBuffer
|
Chris@0
|
41 {
|
Chris@0
|
42 public:
|
Chris@0
|
43 /**
|
Chris@0
|
44 * Create a ring buffer with room to write n samples.
|
Chris@0
|
45 *
|
Chris@0
|
46 * Note that the internal storage size will actually be n+1
|
Chris@0
|
47 * samples, as one element is unavailable for administrative
|
Chris@0
|
48 * reasons. Since the ring buffer performs best if its size is a
|
Chris@0
|
49 * power of two, this means n should ideally be some power of two
|
Chris@0
|
50 * minus one.
|
Chris@0
|
51 */
|
Chris@0
|
52 RingBuffer(size_t n);
|
Chris@0
|
53
|
Chris@0
|
54 virtual ~RingBuffer();
|
Chris@0
|
55
|
Chris@0
|
56 /**
|
Chris@0
|
57 * Return the total capacity of the ring buffer in samples.
|
Chris@0
|
58 * (This is the argument n passed to the constructor.)
|
Chris@0
|
59 */
|
Chris@0
|
60 size_t getSize() const;
|
Chris@0
|
61
|
Chris@0
|
62 /**
|
Chris@0
|
63 * Resize the ring buffer. This also empties it. Actually swaps
|
Chris@0
|
64 * in a new, larger buffer; the old buffer is scavenged after a
|
Chris@0
|
65 * seemly delay. Should be called from the write thread.
|
Chris@0
|
66 */
|
Chris@0
|
67 void resize(size_t newSize);
|
Chris@0
|
68
|
Chris@0
|
69 /**
|
Chris@0
|
70 * Lock the ring buffer into physical memory. Returns true
|
Chris@0
|
71 * for success.
|
Chris@0
|
72 */
|
Chris@0
|
73 bool mlock();
|
Chris@0
|
74
|
Chris@0
|
75 /**
|
Chris@0
|
76 * Reset read and write pointers, thus emptying the buffer.
|
Chris@0
|
77 * Should be called from the write thread.
|
Chris@0
|
78 */
|
Chris@0
|
79 void reset();
|
Chris@0
|
80
|
Chris@0
|
81 /**
|
Chris@0
|
82 * Return the amount of data available for reading by reader R, in
|
Chris@0
|
83 * samples.
|
Chris@0
|
84 */
|
Chris@0
|
85 size_t getReadSpace(int R = 0) const;
|
Chris@0
|
86
|
Chris@0
|
87 /**
|
Chris@0
|
88 * Return the amount of space available for writing, in samples.
|
Chris@0
|
89 */
|
Chris@0
|
90 size_t getWriteSpace() const;
|
Chris@0
|
91
|
Chris@0
|
92 /**
|
Chris@0
|
93 * Read n samples from the buffer, for reader R. If fewer than n
|
Chris@0
|
94 * are available, the remainder will be zeroed out. Returns the
|
Chris@0
|
95 * number of samples actually read.
|
Chris@0
|
96 */
|
Chris@0
|
97 size_t read(T *destination, size_t n, int R = 0);
|
Chris@0
|
98
|
Chris@0
|
99 /**
|
Chris@0
|
100 * Read n samples from the buffer, for reader R, adding them to
|
Chris@0
|
101 * the destination. If fewer than n are available, the remainder
|
Chris@0
|
102 * will be left alone. Returns the number of samples actually
|
Chris@0
|
103 * read.
|
Chris@0
|
104 */
|
Chris@0
|
105 size_t readAdding(T *destination, size_t n, int R = 0);
|
Chris@0
|
106
|
Chris@0
|
107 /**
|
Chris@0
|
108 * Read one sample from the buffer, for reader R. If no sample is
|
Chris@0
|
109 * available, this will silently return zero. Calling this
|
Chris@0
|
110 * repeatedly is obviously slower than calling read once, but it
|
Chris@0
|
111 * may be good enough if you don't want to allocate a buffer to
|
Chris@0
|
112 * read into.
|
Chris@0
|
113 */
|
Chris@0
|
114 T readOne(int R = 0);
|
Chris@0
|
115
|
Chris@0
|
116 /**
|
Chris@0
|
117 * Read n samples from the buffer, if available, for reader R,
|
Chris@0
|
118 * without advancing the read pointer -- i.e. a subsequent read()
|
Chris@0
|
119 * or skip() will be necessary to empty the buffer. If fewer than
|
Chris@0
|
120 * n are available, the remainder will be zeroed out. Returns the
|
Chris@0
|
121 * number of samples actually read.
|
Chris@0
|
122 */
|
Chris@0
|
123 size_t peek(T *destination, size_t n, int R = 0) const;
|
Chris@0
|
124
|
Chris@0
|
125 /**
|
Chris@0
|
126 * Read one sample from the buffer, if available, without
|
Chris@0
|
127 * advancing the read pointer -- i.e. a subsequent read() or
|
Chris@0
|
128 * skip() will be necessary to empty the buffer. Returns zero if
|
Chris@0
|
129 * no sample was available.
|
Chris@0
|
130 */
|
Chris@0
|
131 T peekOne(int R = 0) const;
|
Chris@0
|
132
|
Chris@0
|
133 /**
|
Chris@0
|
134 * Pretend to read n samples from the buffer, for reader R,
|
Chris@0
|
135 * without actually returning them (i.e. discard the next n
|
Chris@0
|
136 * samples). Returns the number of samples actually available for
|
Chris@0
|
137 * discarding.
|
Chris@0
|
138 */
|
Chris@0
|
139 size_t skip(size_t n, int R = 0);
|
Chris@0
|
140
|
Chris@0
|
141 /**
|
Chris@0
|
142 * Write n samples to the buffer. If insufficient space is
|
Chris@0
|
143 * available, not all samples may actually be written. Returns
|
Chris@0
|
144 * the number of samples actually written.
|
Chris@0
|
145 */
|
Chris@0
|
146 size_t write(const T *source, size_t n);
|
Chris@0
|
147
|
Chris@0
|
148 /**
|
Chris@0
|
149 * Write n zero-value samples to the buffer. If insufficient
|
Chris@0
|
150 * space is available, not all zeros may actually be written.
|
Chris@0
|
151 * Returns the number of zeroes actually written.
|
Chris@0
|
152 */
|
Chris@0
|
153 size_t zero(size_t n);
|
Chris@0
|
154
|
Chris@0
|
155 protected:
|
Chris@0
|
156 T *m_buffer;
|
Chris@0
|
157 volatile size_t m_writer;
|
Chris@0
|
158 volatile size_t m_readers[N];
|
Chris@0
|
159 size_t m_size;
|
Chris@0
|
160 bool m_mlocked;
|
Chris@0
|
161
|
Chris@0
|
162 static Scavenger<ScavengerArrayWrapper<T> > m_scavenger;
|
Chris@0
|
163
|
Chris@0
|
164 private:
|
Chris@0
|
165 RingBuffer(const RingBuffer &); // not provided
|
Chris@0
|
166 RingBuffer &operator=(const RingBuffer &); // not provided
|
Chris@0
|
167 };
|
Chris@0
|
168
|
Chris@0
|
169 template <typename T, int N>
|
Chris@0
|
170 Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
|
Chris@0
|
171
|
Chris@0
|
172 template <typename T, int N>
|
Chris@0
|
173 RingBuffer<T, N>::RingBuffer(size_t n) :
|
Chris@0
|
174 m_buffer(new T[n + 1]),
|
Chris@0
|
175 m_writer(0),
|
Chris@0
|
176 m_size(n + 1),
|
Chris@0
|
177 m_mlocked(false)
|
Chris@0
|
178 {
|
Chris@0
|
179 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
180 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
|
Chris@0
|
181 #endif
|
Chris@0
|
182
|
Chris@0
|
183 for (int i = 0; i < N; ++i) m_readers[i] = 0;
|
Chris@0
|
184
|
Chris@0
|
185 m_scavenger.scavenge();
|
Chris@0
|
186 }
|
Chris@0
|
187
|
Chris@0
|
188 template <typename T, int N>
|
Chris@0
|
189 RingBuffer<T, N>::~RingBuffer()
|
Chris@0
|
190 {
|
Chris@0
|
191 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
192 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
|
Chris@0
|
193 #endif
|
Chris@0
|
194
|
Chris@0
|
195 if (m_mlocked) {
|
Chris@0
|
196 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
|
Chris@0
|
197 }
|
Chris@0
|
198 delete[] m_buffer;
|
Chris@0
|
199
|
Chris@0
|
200 m_scavenger.scavenge();
|
Chris@0
|
201 }
|
Chris@0
|
202
|
Chris@0
|
203 template <typename T, int N>
|
Chris@0
|
204 size_t
|
Chris@0
|
205 RingBuffer<T, N>::getSize() const
|
Chris@0
|
206 {
|
Chris@0
|
207 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
208 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
|
Chris@0
|
209 #endif
|
Chris@0
|
210
|
Chris@0
|
211 return m_size - 1;
|
Chris@0
|
212 }
|
Chris@0
|
213
|
Chris@0
|
214 template <typename T, int N>
|
Chris@0
|
215 void
|
Chris@0
|
216 RingBuffer<T, N>::resize(size_t newSize)
|
Chris@0
|
217 {
|
Chris@0
|
218 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
219 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl;
|
Chris@0
|
220 #endif
|
Chris@0
|
221
|
Chris@0
|
222 m_scavenger.scavenge();
|
Chris@0
|
223
|
Chris@0
|
224 if (m_mlocked) {
|
Chris@0
|
225 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
|
Chris@0
|
226 }
|
Chris@0
|
227
|
Chris@0
|
228 m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer));
|
Chris@0
|
229
|
Chris@0
|
230 reset();
|
Chris@0
|
231 m_buffer = new T[newSize + 1];
|
Chris@0
|
232 m_size = newSize + 1;
|
Chris@0
|
233
|
Chris@0
|
234 if (m_mlocked) {
|
Chris@0
|
235 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) {
|
Chris@0
|
236 m_mlocked = false;
|
Chris@0
|
237 }
|
Chris@0
|
238 }
|
Chris@0
|
239 }
|
Chris@0
|
240
|
Chris@0
|
241 template <typename T, int N>
|
Chris@0
|
242 bool
|
Chris@0
|
243 RingBuffer<T, N>::mlock()
|
Chris@0
|
244 {
|
Chris@0
|
245 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
|
Chris@0
|
246 m_mlocked = true;
|
Chris@0
|
247 return true;
|
Chris@0
|
248 }
|
Chris@0
|
249
|
Chris@0
|
250 template <typename T, int N>
|
Chris@0
|
251 void
|
Chris@0
|
252 RingBuffer<T, N>::reset()
|
Chris@0
|
253 {
|
Chris@0
|
254 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
255 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
|
Chris@0
|
256 #endif
|
Chris@0
|
257
|
Chris@0
|
258 m_writer = 0;
|
Chris@0
|
259 for (int i = 0; i < N; ++i) m_readers[i] = 0;
|
Chris@0
|
260 }
|
Chris@0
|
261
|
Chris@0
|
262 template <typename T, int N>
|
Chris@0
|
263 size_t
|
Chris@0
|
264 RingBuffer<T, N>::getReadSpace(int R) const
|
Chris@0
|
265 {
|
Chris@0
|
266 size_t writer = m_writer;
|
Chris@0
|
267 size_t reader = m_readers[R];
|
Chris@0
|
268 size_t space = 0;
|
Chris@0
|
269
|
Chris@0
|
270 if (writer > reader) space = writer - reader;
|
Chris@0
|
271 else space = ((writer + m_size) - reader) % m_size;
|
Chris@0
|
272
|
Chris@0
|
273 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
274 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
|
Chris@0
|
275 #endif
|
Chris@0
|
276
|
Chris@0
|
277 return space;
|
Chris@0
|
278 }
|
Chris@0
|
279
|
Chris@0
|
280 template <typename T, int N>
|
Chris@0
|
281 size_t
|
Chris@0
|
282 RingBuffer<T, N>::getWriteSpace() const
|
Chris@0
|
283 {
|
Chris@0
|
284 size_t space = 0;
|
Chris@0
|
285 for (int i = 0; i < N; ++i) {
|
Chris@0
|
286 size_t here = (m_readers[i] + m_size - m_writer - 1) % m_size;
|
Chris@0
|
287 if (i == 0 || here < space) space = here;
|
Chris@0
|
288 }
|
Chris@0
|
289
|
Chris@0
|
290 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
291 size_t rs(getReadSpace()), rp(m_readers[0]);
|
Chris@0
|
292
|
Chris@0
|
293 std::cerr << "RingBuffer: write space " << space << ", read space "
|
Chris@0
|
294 << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
|
Chris@0
|
295 std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
|
Chris@0
|
296 #endif
|
Chris@0
|
297
|
Chris@0
|
298 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
299 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
|
Chris@0
|
300 #endif
|
Chris@0
|
301
|
Chris@0
|
302 return space;
|
Chris@0
|
303 }
|
Chris@0
|
304
|
Chris@0
|
305 template <typename T, int N>
|
Chris@0
|
306 size_t
|
Chris@0
|
307 RingBuffer<T, N>::read(T *destination, size_t n, int R)
|
Chris@0
|
308 {
|
Chris@0
|
309 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
310 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
311 #endif
|
Chris@0
|
312
|
Chris@0
|
313 size_t available = getReadSpace(R);
|
Chris@0
|
314 if (n > available) {
|
Chris@0
|
315 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
316 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@0
|
317 << std::endl;
|
Chris@0
|
318 #endif
|
Chris@0
|
319 memset(destination + available, 0, (n - available) * sizeof(T));
|
Chris@0
|
320 n = available;
|
Chris@0
|
321 }
|
Chris@0
|
322 if (n == 0) return n;
|
Chris@0
|
323
|
Chris@0
|
324 size_t here = m_size - m_readers[R];
|
Chris@0
|
325 if (here >= n) {
|
Chris@0
|
326 memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
|
Chris@0
|
327 } else {
|
Chris@0
|
328 memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
|
Chris@0
|
329 memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
|
Chris@0
|
330 }
|
Chris@0
|
331
|
Chris@0
|
332 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
333
|
Chris@0
|
334 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
335 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
|
Chris@0
|
336 #endif
|
Chris@0
|
337
|
Chris@0
|
338 return n;
|
Chris@0
|
339 }
|
Chris@0
|
340
|
Chris@0
|
341 template <typename T, int N>
|
Chris@0
|
342 size_t
|
Chris@0
|
343 RingBuffer<T, N>::readAdding(T *destination, size_t n, int R)
|
Chris@0
|
344 {
|
Chris@0
|
345 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
346 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
347 #endif
|
Chris@0
|
348
|
Chris@0
|
349 size_t available = getReadSpace(R);
|
Chris@0
|
350 if (n > available) {
|
Chris@0
|
351 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
352 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@0
|
353 << std::endl;
|
Chris@0
|
354 #endif
|
Chris@0
|
355 n = available;
|
Chris@0
|
356 }
|
Chris@0
|
357 if (n == 0) return n;
|
Chris@0
|
358
|
Chris@0
|
359 size_t here = m_size - m_readers[R];
|
Chris@0
|
360
|
Chris@0
|
361 if (here >= n) {
|
Chris@0
|
362 for (size_t i = 0; i < n; ++i) {
|
Chris@0
|
363 destination[i] += (m_buffer + m_readers[R])[i];
|
Chris@0
|
364 }
|
Chris@0
|
365 } else {
|
Chris@0
|
366 for (size_t i = 0; i < here; ++i) {
|
Chris@0
|
367 destination[i] += (m_buffer + m_readers[R])[i];
|
Chris@0
|
368 }
|
Chris@0
|
369 for (size_t i = 0; i < (n - here); ++i) {
|
Chris@0
|
370 destination[i + here] += m_buffer[i];
|
Chris@0
|
371 }
|
Chris@0
|
372 }
|
Chris@0
|
373
|
Chris@0
|
374 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
375 return n;
|
Chris@0
|
376 }
|
Chris@0
|
377
|
Chris@0
|
378 template <typename T, int N>
|
Chris@0
|
379 T
|
Chris@0
|
380 RingBuffer<T, N>::readOne(int R)
|
Chris@0
|
381 {
|
Chris@0
|
382 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
383 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
|
Chris@0
|
384 #endif
|
Chris@0
|
385
|
Chris@0
|
386 if (m_writer == m_readers[R]) {
|
Chris@0
|
387 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
388 std::cerr << "WARNING: No sample available"
|
Chris@0
|
389 << std::endl;
|
Chris@0
|
390 #endif
|
Chris@0
|
391 T t;
|
Chris@0
|
392 memset(&t, 0, sizeof(T));
|
Chris@0
|
393 return t;
|
Chris@0
|
394 }
|
Chris@0
|
395 T value = m_buffer[m_readers[R]];
|
Chris@0
|
396 if (++m_readers[R] == m_size) m_readers[R] = 0;
|
Chris@0
|
397 return value;
|
Chris@0
|
398 }
|
Chris@0
|
399
|
Chris@0
|
400 template <typename T, int N>
|
Chris@0
|
401 size_t
|
Chris@0
|
402 RingBuffer<T, N>::peek(T *destination, size_t n, int R) const
|
Chris@0
|
403 {
|
Chris@0
|
404 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
405 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
406 #endif
|
Chris@0
|
407
|
Chris@0
|
408 size_t available = getReadSpace(R);
|
Chris@0
|
409 if (n > available) {
|
Chris@0
|
410 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
411 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@0
|
412 << std::endl;
|
Chris@0
|
413 #endif
|
Chris@0
|
414 memset(destination + available, 0, (n - available) * sizeof(T));
|
Chris@0
|
415 n = available;
|
Chris@0
|
416 }
|
Chris@0
|
417 if (n == 0) return n;
|
Chris@0
|
418
|
Chris@0
|
419 size_t here = m_size - m_readers[R];
|
Chris@0
|
420 if (here >= n) {
|
Chris@0
|
421 memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
|
Chris@0
|
422 } else {
|
Chris@0
|
423 memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
|
Chris@0
|
424 memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
|
Chris@0
|
425 }
|
Chris@0
|
426
|
Chris@0
|
427 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
428 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
|
Chris@0
|
429 #endif
|
Chris@0
|
430
|
Chris@0
|
431 return n;
|
Chris@0
|
432 }
|
Chris@0
|
433
|
Chris@0
|
434 template <typename T, int N>
|
Chris@0
|
435 T
|
Chris@0
|
436 RingBuffer<T, N>::peekOne(int R) const
|
Chris@0
|
437 {
|
Chris@0
|
438 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
439 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
|
Chris@0
|
440 #endif
|
Chris@0
|
441
|
Chris@0
|
442 if (m_writer == m_readers[R]) {
|
Chris@0
|
443 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
444 std::cerr << "WARNING: No sample available"
|
Chris@0
|
445 << std::endl;
|
Chris@0
|
446 #endif
|
Chris@0
|
447 T t;
|
Chris@0
|
448 memset(&t, 0, sizeof(T));
|
Chris@0
|
449 return t;
|
Chris@0
|
450 }
|
Chris@0
|
451 T value = m_buffer[m_readers[R]];
|
Chris@0
|
452 return value;
|
Chris@0
|
453 }
|
Chris@0
|
454
|
Chris@0
|
455 template <typename T, int N>
|
Chris@0
|
456 size_t
|
Chris@0
|
457 RingBuffer<T, N>::skip(size_t n, int R)
|
Chris@0
|
458 {
|
Chris@0
|
459 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
460 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
|
Chris@0
|
461 #endif
|
Chris@0
|
462
|
Chris@0
|
463 size_t available = getReadSpace(R);
|
Chris@0
|
464 if (n > available) {
|
Chris@0
|
465 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
466 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@0
|
467 << std::endl;
|
Chris@0
|
468 #endif
|
Chris@0
|
469 n = available;
|
Chris@0
|
470 }
|
Chris@0
|
471 if (n == 0) return n;
|
Chris@0
|
472 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
473 return n;
|
Chris@0
|
474 }
|
Chris@0
|
475
|
Chris@0
|
476 template <typename T, int N>
|
Chris@0
|
477 size_t
|
Chris@0
|
478 RingBuffer<T, N>::write(const T *source, size_t n)
|
Chris@0
|
479 {
|
Chris@0
|
480 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
481 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
|
Chris@0
|
482 #endif
|
Chris@0
|
483
|
Chris@0
|
484 size_t available = getWriteSpace();
|
Chris@0
|
485 if (n > available) {
|
Chris@0
|
486 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
487 std::cerr << "WARNING: Only room for " << available << " samples"
|
Chris@0
|
488 << std::endl;
|
Chris@0
|
489 #endif
|
Chris@0
|
490 n = available;
|
Chris@0
|
491 }
|
Chris@0
|
492 if (n == 0) return n;
|
Chris@0
|
493
|
Chris@0
|
494 size_t here = m_size - m_writer;
|
Chris@0
|
495 if (here >= n) {
|
Chris@0
|
496 memcpy(m_buffer + m_writer, source, n * sizeof(T));
|
Chris@0
|
497 } else {
|
Chris@0
|
498 memcpy(m_buffer + m_writer, source, here * sizeof(T));
|
Chris@0
|
499 memcpy(m_buffer, source + here, (n - here) * sizeof(T));
|
Chris@0
|
500 }
|
Chris@0
|
501
|
Chris@0
|
502 m_writer = (m_writer + n) % m_size;
|
Chris@0
|
503
|
Chris@0
|
504 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
505 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
|
Chris@0
|
506 #endif
|
Chris@0
|
507
|
Chris@0
|
508 return n;
|
Chris@0
|
509 }
|
Chris@0
|
510
|
Chris@0
|
511 template <typename T, int N>
|
Chris@0
|
512 size_t
|
Chris@0
|
513 RingBuffer<T, N>::zero(size_t n)
|
Chris@0
|
514 {
|
Chris@0
|
515 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
516 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
|
Chris@0
|
517 #endif
|
Chris@0
|
518
|
Chris@0
|
519 size_t available = getWriteSpace();
|
Chris@0
|
520 if (n > available) {
|
Chris@0
|
521 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
522 std::cerr << "WARNING: Only room for " << available << " samples"
|
Chris@0
|
523 << std::endl;
|
Chris@0
|
524 #endif
|
Chris@0
|
525 n = available;
|
Chris@0
|
526 }
|
Chris@0
|
527 if (n == 0) return n;
|
Chris@0
|
528
|
Chris@0
|
529 size_t here = m_size - m_writer;
|
Chris@0
|
530 if (here >= n) {
|
Chris@0
|
531 memset(m_buffer + m_writer, 0, n * sizeof(T));
|
Chris@0
|
532 } else {
|
Chris@0
|
533 memset(m_buffer + m_writer, 0, here * sizeof(T));
|
Chris@0
|
534 memset(m_buffer, 0, (n - here) * sizeof(T));
|
Chris@0
|
535 }
|
Chris@0
|
536
|
Chris@0
|
537 m_writer = (m_writer + n) % m_size;
|
Chris@0
|
538 return n;
|
Chris@0
|
539 }
|
Chris@0
|
540
|
Chris@0
|
541 #endif // _RINGBUFFER_H_
|