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