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@1827
|
29 #include <bqvec/VectorOps.h>
|
Chris@1553
|
30
|
Chris@1827
|
31 #include <vector>
|
Chris@485
|
32
|
Chris@0
|
33 //#define DEBUG_RINGBUFFER 1
|
Chris@0
|
34
|
Chris@0
|
35 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
36 #include <iostream>
|
Chris@0
|
37 #endif
|
Chris@0
|
38
|
Chris@0
|
39 /**
|
Chris@0
|
40 * RingBuffer implements a lock-free ring buffer for one writer and N
|
Chris@0
|
41 * readers, that is to be used to store a sample type T.
|
Chris@0
|
42 */
|
Chris@0
|
43
|
Chris@0
|
44 template <typename T, int N = 1>
|
Chris@0
|
45 class RingBuffer
|
Chris@0
|
46 {
|
Chris@0
|
47 public:
|
Chris@0
|
48 /**
|
Chris@0
|
49 * Create a ring buffer with room to write n samples.
|
Chris@0
|
50 *
|
Chris@0
|
51 * Note that the internal storage size will actually be n+1
|
Chris@0
|
52 * samples, as one element is unavailable for administrative
|
Chris@0
|
53 * reasons. Since the ring buffer performs best if its size is a
|
Chris@0
|
54 * power of two, this means n should ideally be some power of two
|
Chris@0
|
55 * minus one.
|
Chris@0
|
56 */
|
Chris@928
|
57 RingBuffer(int n);
|
Chris@0
|
58
|
Chris@0
|
59 virtual ~RingBuffer();
|
Chris@0
|
60
|
Chris@0
|
61 /**
|
Chris@0
|
62 * Return the total capacity of the ring buffer in samples.
|
Chris@0
|
63 * (This is the argument n passed to the constructor.)
|
Chris@0
|
64 */
|
Chris@928
|
65 int getSize() const;
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@1827
|
68 * Return a new ring buffer of the given size, containing the same
|
Chris@1827
|
69 * data as this one as perceived by reader 0 of this buffer. If
|
Chris@1827
|
70 * another thread reads from or writes to this buffer during the
|
Chris@1827
|
71 * call, the contents of the new buffer may be incomplete or
|
Chris@835
|
72 * inconsistent. If this buffer's data will not fit in the new
|
Chris@1827
|
73 * size, the contents are undetermined.
|
Chris@0
|
74 */
|
Chris@1827
|
75 RingBuffer<T, N> resized(int newSize) const;
|
Chris@0
|
76
|
Chris@0
|
77 /**
|
Chris@0
|
78 * Reset read and write pointers, thus emptying the buffer.
|
Chris@0
|
79 * Should be called from the write thread.
|
Chris@0
|
80 */
|
Chris@0
|
81 void reset();
|
Chris@0
|
82
|
Chris@0
|
83 /**
|
Chris@0
|
84 * Return the amount of data available for reading by reader R, in
|
Chris@0
|
85 * samples.
|
Chris@0
|
86 */
|
Chris@928
|
87 int getReadSpace(int R = 0) const;
|
Chris@0
|
88
|
Chris@0
|
89 /**
|
Chris@0
|
90 * Return the amount of space available for writing, in samples.
|
Chris@0
|
91 */
|
Chris@928
|
92 int getWriteSpace() const;
|
Chris@0
|
93
|
Chris@0
|
94 /**
|
Chris@0
|
95 * Read n samples from the buffer, for reader R. If fewer than n
|
Chris@0
|
96 * are available, the remainder will be zeroed out. Returns the
|
Chris@0
|
97 * number of samples actually read.
|
Chris@0
|
98 */
|
Chris@928
|
99 int read(T *destination, int n, int R = 0);
|
Chris@0
|
100
|
Chris@0
|
101 /**
|
Chris@0
|
102 * Read n samples from the buffer, for reader R, adding them to
|
Chris@0
|
103 * the destination. If fewer than n are available, the remainder
|
Chris@0
|
104 * will be left alone. Returns the number of samples actually
|
Chris@0
|
105 * read.
|
Chris@0
|
106 */
|
Chris@928
|
107 int readAdding(T *destination, int n, int R = 0);
|
Chris@0
|
108
|
Chris@0
|
109 /**
|
Chris@0
|
110 * Read one sample from the buffer, for reader R. If no sample is
|
Chris@0
|
111 * available, this will silently return zero. Calling this
|
Chris@0
|
112 * repeatedly is obviously slower than calling read once, but it
|
Chris@0
|
113 * may be good enough if you don't want to allocate a buffer to
|
Chris@0
|
114 * read into.
|
Chris@0
|
115 */
|
Chris@0
|
116 T readOne(int R = 0);
|
Chris@0
|
117
|
Chris@0
|
118 /**
|
Chris@0
|
119 * Read n samples from the buffer, if available, for reader R,
|
Chris@0
|
120 * without advancing the read pointer -- i.e. a subsequent read()
|
Chris@0
|
121 * or skip() will be necessary to empty the buffer. If fewer than
|
Chris@0
|
122 * n are available, the remainder will be zeroed out. Returns the
|
Chris@0
|
123 * number of samples actually read.
|
Chris@0
|
124 */
|
Chris@928
|
125 int peek(T *destination, int n, int R = 0) const;
|
Chris@0
|
126
|
Chris@0
|
127 /**
|
Chris@0
|
128 * Read one sample from the buffer, if available, without
|
Chris@0
|
129 * advancing the read pointer -- i.e. a subsequent read() or
|
Chris@0
|
130 * skip() will be necessary to empty the buffer. Returns zero if
|
Chris@0
|
131 * no sample was available.
|
Chris@0
|
132 */
|
Chris@0
|
133 T peekOne(int R = 0) const;
|
Chris@0
|
134
|
Chris@0
|
135 /**
|
Chris@0
|
136 * Pretend to read n samples from the buffer, for reader R,
|
Chris@0
|
137 * without actually returning them (i.e. discard the next n
|
Chris@0
|
138 * samples). Returns the number of samples actually available for
|
Chris@0
|
139 * discarding.
|
Chris@0
|
140 */
|
Chris@928
|
141 int skip(int n, int R = 0);
|
Chris@0
|
142
|
Chris@0
|
143 /**
|
Chris@0
|
144 * Write n samples to the buffer. If insufficient space is
|
Chris@0
|
145 * available, not all samples may actually be written. Returns
|
Chris@0
|
146 * the number of samples actually written.
|
Chris@0
|
147 */
|
Chris@928
|
148 int write(const T *source, int n);
|
Chris@0
|
149
|
Chris@0
|
150 /**
|
Chris@0
|
151 * Write n zero-value samples to the buffer. If insufficient
|
Chris@0
|
152 * space is available, not all zeros may actually be written.
|
Chris@0
|
153 * Returns the number of zeroes actually written.
|
Chris@0
|
154 */
|
Chris@928
|
155 int zero(int n);
|
Chris@0
|
156
|
Chris@1827
|
157 RingBuffer(const RingBuffer &) =default;
|
Chris@1827
|
158 RingBuffer &operator=(const RingBuffer &) =default;
|
Chris@1827
|
159
|
Chris@0
|
160 protected:
|
Chris@1829
|
161 std::vector<T, breakfastquay::StlAllocator<T>> m_buffer;
|
Chris@1827
|
162 int m_writer;
|
Chris@1827
|
163 std::vector<int> m_readers;
|
Chris@1827
|
164 int m_size;
|
Chris@0
|
165 };
|
Chris@0
|
166
|
Chris@0
|
167 template <typename T, int N>
|
Chris@928
|
168 RingBuffer<T, N>::RingBuffer(int n) :
|
Chris@1827
|
169 m_buffer(n + 1, T()),
|
Chris@0
|
170 m_writer(0),
|
Chris@1827
|
171 m_readers(N, 0),
|
Chris@574
|
172 m_size(n + 1)
|
Chris@0
|
173 {
|
Chris@0
|
174 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
175 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
|
Chris@0
|
176 #endif
|
Chris@0
|
177 }
|
Chris@0
|
178
|
Chris@0
|
179 template <typename T, int N>
|
Chris@0
|
180 RingBuffer<T, N>::~RingBuffer()
|
Chris@0
|
181 {
|
Chris@0
|
182 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
183 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
|
Chris@0
|
184 #endif
|
Chris@0
|
185 }
|
Chris@0
|
186
|
Chris@0
|
187 template <typename T, int N>
|
Chris@928
|
188 int
|
Chris@0
|
189 RingBuffer<T, N>::getSize() const
|
Chris@0
|
190 {
|
Chris@0
|
191 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
192 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
|
Chris@0
|
193 #endif
|
Chris@0
|
194
|
Chris@0
|
195 return m_size - 1;
|
Chris@0
|
196 }
|
Chris@0
|
197
|
Chris@0
|
198 template <typename T, int N>
|
Chris@1827
|
199 RingBuffer<T, N>
|
Chris@928
|
200 RingBuffer<T, N>::resized(int newSize) const
|
Chris@0
|
201 {
|
Chris@0
|
202 #ifdef DEBUG_RINGBUFFER
|
Chris@835
|
203 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resized(" << newSize << ")" << std::endl;
|
Chris@0
|
204 #endif
|
Chris@0
|
205
|
Chris@1827
|
206 RingBuffer<T, N> newBuffer(newSize);
|
Chris@0
|
207
|
Chris@835
|
208 int w = m_writer;
|
Chris@835
|
209 int r = m_readers[0];
|
Chris@835
|
210
|
Chris@835
|
211 while (r != w) {
|
Chris@835
|
212 T value = m_buffer[r];
|
Chris@835
|
213 newBuffer->write(&value, 1);
|
Chris@835
|
214 if (++r == m_size) r = 0;
|
Chris@0
|
215 }
|
Chris@0
|
216
|
Chris@835
|
217 return newBuffer;
|
Chris@0
|
218 }
|
Chris@0
|
219
|
Chris@0
|
220 template <typename T, int N>
|
Chris@0
|
221 void
|
Chris@0
|
222 RingBuffer<T, N>::reset()
|
Chris@0
|
223 {
|
Chris@0
|
224 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
225 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
|
Chris@0
|
226 #endif
|
Chris@0
|
227
|
Chris@0
|
228 m_writer = 0;
|
Chris@1827
|
229 for (int i = 0; i < N; ++i) {
|
Chris@1827
|
230 m_readers[i] = 0;
|
Chris@1827
|
231 }
|
Chris@0
|
232 }
|
Chris@0
|
233
|
Chris@0
|
234 template <typename T, int N>
|
Chris@928
|
235 int
|
Chris@0
|
236 RingBuffer<T, N>::getReadSpace(int R) const
|
Chris@0
|
237 {
|
Chris@928
|
238 int writer = m_writer;
|
Chris@928
|
239 int reader = m_readers[R];
|
Chris@928
|
240 int space = 0;
|
Chris@0
|
241
|
Chris@0
|
242 if (writer > reader) space = writer - reader;
|
Chris@0
|
243 else space = ((writer + m_size) - reader) % m_size;
|
Chris@0
|
244
|
Chris@0
|
245 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
246 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
|
Chris@0
|
247 #endif
|
Chris@0
|
248
|
Chris@0
|
249 return space;
|
Chris@0
|
250 }
|
Chris@0
|
251
|
Chris@0
|
252 template <typename T, int N>
|
Chris@928
|
253 int
|
Chris@0
|
254 RingBuffer<T, N>::getWriteSpace() const
|
Chris@0
|
255 {
|
Chris@928
|
256 int space = 0;
|
Chris@0
|
257 for (int i = 0; i < N; ++i) {
|
Chris@1429
|
258 int here = (m_readers[i] + m_size - m_writer - 1) % m_size;
|
Chris@1429
|
259 if (i == 0 || here < space) space = here;
|
Chris@0
|
260 }
|
Chris@0
|
261
|
Chris@0
|
262 #ifdef DEBUG_RINGBUFFER
|
Chris@928
|
263 int rs(getReadSpace()), rp(m_readers[0]);
|
Chris@0
|
264
|
Chris@0
|
265 std::cerr << "RingBuffer: write space " << space << ", read space "
|
Chris@1429
|
266 << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
|
Chris@0
|
267 std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
|
Chris@0
|
268 #endif
|
Chris@0
|
269
|
Chris@0
|
270 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
271 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
|
Chris@0
|
272 #endif
|
Chris@0
|
273
|
Chris@0
|
274 return space;
|
Chris@0
|
275 }
|
Chris@0
|
276
|
Chris@0
|
277 template <typename T, int N>
|
Chris@928
|
278 int
|
Chris@928
|
279 RingBuffer<T, N>::read(T *destination, int n, int R)
|
Chris@0
|
280 {
|
Chris@0
|
281 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
282 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
283 #endif
|
Chris@0
|
284
|
Chris@928
|
285 int available = getReadSpace(R);
|
Chris@0
|
286 if (n > available) {
|
Chris@0
|
287 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
288 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@1429
|
289 << std::endl;
|
Chris@0
|
290 #endif
|
Chris@1827
|
291 breakfastquay::v_zero(destination + available, n - available);
|
Chris@1429
|
292 n = available;
|
Chris@0
|
293 }
|
Chris@0
|
294 if (n == 0) return n;
|
Chris@0
|
295
|
Chris@928
|
296 int here = m_size - m_readers[R];
|
Chris@0
|
297 if (here >= n) {
|
Chris@1827
|
298 breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], n);
|
Chris@0
|
299 } else {
|
Chris@1827
|
300 breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], here);
|
Chris@1827
|
301 breakfastquay::v_copy(destination + here, m_buffer.data(), n - here);
|
Chris@0
|
302 }
|
Chris@0
|
303
|
Chris@1553
|
304 BQ_MBARRIER();
|
Chris@0
|
305 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
306
|
Chris@0
|
307 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
308 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
|
Chris@0
|
309 #endif
|
Chris@0
|
310
|
Chris@0
|
311 return n;
|
Chris@0
|
312 }
|
Chris@0
|
313
|
Chris@0
|
314 template <typename T, int N>
|
Chris@928
|
315 int
|
Chris@928
|
316 RingBuffer<T, N>::readAdding(T *destination, int n, int R)
|
Chris@0
|
317 {
|
Chris@0
|
318 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
319 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
320 #endif
|
Chris@0
|
321
|
Chris@928
|
322 int available = getReadSpace(R);
|
Chris@0
|
323 if (n > available) {
|
Chris@0
|
324 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
325 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@1429
|
326 << std::endl;
|
Chris@0
|
327 #endif
|
Chris@1429
|
328 n = available;
|
Chris@0
|
329 }
|
Chris@0
|
330 if (n == 0) return n;
|
Chris@0
|
331
|
Chris@928
|
332 int here = m_size - m_readers[R];
|
Chris@0
|
333
|
Chris@0
|
334 if (here >= n) {
|
Chris@1429
|
335 for (int i = 0; i < n; ++i) {
|
Chris@1827
|
336 destination[i] += (m_buffer.data() + m_readers[R])[i];
|
Chris@1429
|
337 }
|
Chris@0
|
338 } else {
|
Chris@1429
|
339 for (int i = 0; i < here; ++i) {
|
Chris@1827
|
340 destination[i] += (m_buffer.data() + m_readers[R])[i];
|
Chris@1429
|
341 }
|
Chris@1429
|
342 for (int i = 0; i < (n - here); ++i) {
|
Chris@1429
|
343 destination[i + here] += m_buffer[i];
|
Chris@1429
|
344 }
|
Chris@0
|
345 }
|
Chris@0
|
346
|
Chris@1553
|
347 BQ_MBARRIER();
|
Chris@0
|
348 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
349 return n;
|
Chris@0
|
350 }
|
Chris@0
|
351
|
Chris@0
|
352 template <typename T, int N>
|
Chris@0
|
353 T
|
Chris@0
|
354 RingBuffer<T, N>::readOne(int R)
|
Chris@0
|
355 {
|
Chris@0
|
356 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
357 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
|
Chris@0
|
358 #endif
|
Chris@0
|
359
|
Chris@0
|
360 if (m_writer == m_readers[R]) {
|
Chris@0
|
361 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
362 std::cerr << "WARNING: No sample available"
|
Chris@1429
|
363 << std::endl;
|
Chris@0
|
364 #endif
|
Chris@1827
|
365 return T();
|
Chris@0
|
366 }
|
Chris@0
|
367 T value = m_buffer[m_readers[R]];
|
Chris@1553
|
368 BQ_MBARRIER();
|
Chris@0
|
369 if (++m_readers[R] == m_size) m_readers[R] = 0;
|
Chris@0
|
370 return value;
|
Chris@0
|
371 }
|
Chris@0
|
372
|
Chris@0
|
373 template <typename T, int N>
|
Chris@928
|
374 int
|
Chris@928
|
375 RingBuffer<T, N>::peek(T *destination, int n, int R) const
|
Chris@0
|
376 {
|
Chris@0
|
377 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
378 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
|
Chris@0
|
379 #endif
|
Chris@0
|
380
|
Chris@928
|
381 int available = getReadSpace(R);
|
Chris@0
|
382 if (n > available) {
|
Chris@0
|
383 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
384 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@1429
|
385 << std::endl;
|
Chris@0
|
386 #endif
|
Chris@1827
|
387 breakfastquay::v_zero(destination + available, n - available);
|
Chris@1429
|
388 n = available;
|
Chris@0
|
389 }
|
Chris@0
|
390 if (n == 0) return n;
|
Chris@0
|
391
|
Chris@928
|
392 int here = m_size - m_readers[R];
|
Chris@0
|
393 if (here >= n) {
|
Chris@1827
|
394 breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], n);
|
Chris@0
|
395 } else {
|
Chris@1827
|
396 breakfastquay::v_copy(destination, m_buffer.data() + m_readers[R], here);
|
Chris@1827
|
397 breakfastquay::v_copy(destination + here, m_buffer.data(), n - here);
|
Chris@0
|
398 }
|
Chris@0
|
399
|
Chris@0
|
400 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
401 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
|
Chris@0
|
402 #endif
|
Chris@0
|
403
|
Chris@0
|
404 return n;
|
Chris@0
|
405 }
|
Chris@0
|
406
|
Chris@0
|
407 template <typename T, int N>
|
Chris@0
|
408 T
|
Chris@0
|
409 RingBuffer<T, N>::peekOne(int R) const
|
Chris@0
|
410 {
|
Chris@0
|
411 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
412 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
|
Chris@0
|
413 #endif
|
Chris@0
|
414
|
Chris@0
|
415 if (m_writer == m_readers[R]) {
|
Chris@0
|
416 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
417 std::cerr << "WARNING: No sample available"
|
Chris@1429
|
418 << std::endl;
|
Chris@0
|
419 #endif
|
Chris@1827
|
420 return T();
|
Chris@0
|
421 }
|
Chris@0
|
422 T value = m_buffer[m_readers[R]];
|
Chris@0
|
423 return value;
|
Chris@0
|
424 }
|
Chris@0
|
425
|
Chris@0
|
426 template <typename T, int N>
|
Chris@928
|
427 int
|
Chris@928
|
428 RingBuffer<T, N>::skip(int n, int R)
|
Chris@0
|
429 {
|
Chris@0
|
430 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
431 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
|
Chris@0
|
432 #endif
|
Chris@0
|
433
|
Chris@928
|
434 int available = getReadSpace(R);
|
Chris@0
|
435 if (n > available) {
|
Chris@0
|
436 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
437 std::cerr << "WARNING: Only " << available << " samples available"
|
Chris@1429
|
438 << std::endl;
|
Chris@0
|
439 #endif
|
Chris@1429
|
440 n = available;
|
Chris@0
|
441 }
|
Chris@0
|
442 if (n == 0) return n;
|
Chris@0
|
443 m_readers[R] = (m_readers[R] + n) % m_size;
|
Chris@0
|
444 return n;
|
Chris@0
|
445 }
|
Chris@0
|
446
|
Chris@0
|
447 template <typename T, int N>
|
Chris@928
|
448 int
|
Chris@928
|
449 RingBuffer<T, N>::write(const T *source, int n)
|
Chris@0
|
450 {
|
Chris@0
|
451 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
452 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
|
Chris@0
|
453 #endif
|
Chris@0
|
454
|
Chris@928
|
455 int available = getWriteSpace();
|
Chris@0
|
456 if (n > available) {
|
Chris@0
|
457 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
458 std::cerr << "WARNING: Only room for " << available << " samples"
|
Chris@1429
|
459 << std::endl;
|
Chris@0
|
460 #endif
|
Chris@1429
|
461 n = available;
|
Chris@0
|
462 }
|
Chris@0
|
463 if (n == 0) return n;
|
Chris@0
|
464
|
Chris@928
|
465 int here = m_size - m_writer;
|
Chris@0
|
466 if (here >= n) {
|
Chris@1827
|
467 breakfastquay::v_copy(m_buffer.data() + m_writer, source, n);
|
Chris@0
|
468 } else {
|
Chris@1827
|
469 breakfastquay::v_copy(m_buffer.data() + m_writer, source, here);
|
Chris@1827
|
470 breakfastquay::v_copy(m_buffer.data(), source + here, n - here);
|
Chris@0
|
471 }
|
Chris@0
|
472
|
Chris@1553
|
473 BQ_MBARRIER();
|
Chris@0
|
474 m_writer = (m_writer + n) % m_size;
|
Chris@0
|
475
|
Chris@0
|
476 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
477 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
|
Chris@0
|
478 #endif
|
Chris@0
|
479
|
Chris@0
|
480 return n;
|
Chris@0
|
481 }
|
Chris@0
|
482
|
Chris@0
|
483 template <typename T, int N>
|
Chris@928
|
484 int
|
Chris@928
|
485 RingBuffer<T, N>::zero(int n)
|
Chris@0
|
486 {
|
Chris@0
|
487 #ifdef DEBUG_RINGBUFFER
|
Chris@0
|
488 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
|
Chris@0
|
489 #endif
|
Chris@0
|
490
|
Chris@928
|
491 int available = getWriteSpace();
|
Chris@0
|
492 if (n > available) {
|
Chris@0
|
493 #ifdef DEBUG_RINGBUFFER
|
Chris@1429
|
494 std::cerr << "WARNING: Only room for " << available << " samples"
|
Chris@1429
|
495 << std::endl;
|
Chris@0
|
496 #endif
|
Chris@1429
|
497 n = available;
|
Chris@0
|
498 }
|
Chris@0
|
499 if (n == 0) return n;
|
Chris@0
|
500
|
Chris@928
|
501 int here = m_size - m_writer;
|
Chris@0
|
502 if (here >= n) {
|
Chris@1827
|
503 breakfastquay::v_zero(m_buffer.data() + m_writer, n);
|
Chris@0
|
504 } else {
|
Chris@1827
|
505 breakfastquay::v_zero(m_buffer.data() + m_writer, here);
|
Chris@1827
|
506 breakfastquay::v_zero(m_buffer.data(), n - here);
|
Chris@0
|
507 }
|
Chris@835
|
508
|
Chris@1553
|
509 BQ_MBARRIER();
|
Chris@0
|
510 m_writer = (m_writer + n) % m_size;
|
Chris@0
|
511 return n;
|
Chris@0
|
512 }
|
Chris@0
|
513
|
Chris@0
|
514 #endif // _RINGBUFFER_H_
|