svcore  1.9
RingBuffer.h
Go to the documentation of this file.
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
2 
3 /*
4  Sonic Visualiser
5  An audio file viewer and annotation editor.
6  Centre for Digital Music, Queen Mary, University of London.
7 
8  This program is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 2 of the
11  License, or (at your option) any later version. See the file
12  COPYING included with this distribution for more information.
13 */
14 
15 /*
16  This is a modified version of a source file from the
17  Rosegarden MIDI and audio sequencer and notation editor.
18  This file copyright 2000-2006 Chris Cannam.
19 */
20 
21 #ifndef _RINGBUFFER_H_
22 #define _RINGBUFFER_H_
23 
24 #include <sys/types.h>
25 
26 #include "system/System.h"
27 
28 #include <cstring> // memcpy, memset &c
29 
30 //#define DEBUG_RINGBUFFER 1
31 
32 #ifdef DEBUG_RINGBUFFER
33 #include <iostream>
34 #endif
35 
45 template <typename T, int N = 1>
47 {
48 public:
58  RingBuffer(int n);
59 
60  virtual ~RingBuffer();
61 
66  int getSize() const;
67 
77  RingBuffer<T, N> *resized(int newSize) const;
78 
83  bool mlock();
84 
89  void reset();
90 
95  int getReadSpace(int R = 0) const;
96 
100  int getWriteSpace() const;
101 
107  int read(T *destination, int n, int R = 0);
108 
115  int readAdding(T *destination, int n, int R = 0);
116 
124  T readOne(int R = 0);
125 
133  int peek(T *destination, int n, int R = 0) const;
134 
141  T peekOne(int R = 0) const;
142 
149  int skip(int n, int R = 0);
150 
156  int write(const T *source, int n);
157 
163  int zero(int n);
164 
165 protected:
167  bool m_mlocked;
168  int m_writer;
169  int *m_readers;
170  int m_size;
171  int m_spare;
172 
173 private:
174  RingBuffer(const RingBuffer &); // not provided
175  RingBuffer &operator=(const RingBuffer &); // not provided
176 };
177 
178 template <typename T, int N>
180  m_buffer(new T[n + 1]),
181  m_mlocked(false),
182  m_writer(0),
183  m_readers(new int[N]),
184  m_size(n + 1)
185 {
186 #ifdef DEBUG_RINGBUFFER
187  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
188 #endif
189 /*
190  std::cerr << "note: sizeof(RingBuffer<T,N> = " << sizeof(RingBuffer<T,N>) << ")" << std::endl;
191 
192  std::cerr << "this = " << this << std::endl;
193  std::cerr << "&m_buffer = " << &m_buffer << std::endl;
194  std::cerr << "&m_mlocked = " << &m_mlocked << std::endl;
195  std::cerr << "&m_writer = " << &m_writer << std::endl;
196  std::cerr << "&m_readers = " << &m_readers << std::endl;
197  std::cerr << "&m_size = " << &m_size << std::endl;
198 */
199 
200  for (int i = 0; i < N; ++i) m_readers[i] = 0;
201 }
202 
203 template <typename T, int N>
205 {
206 #ifdef DEBUG_RINGBUFFER
207  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
208 #endif
209 
210  delete[] m_readers;
211 
212  if (m_mlocked) {
213  MUNLOCK((void *)m_buffer, m_size * sizeof(T));
214  }
215  delete[] m_buffer;
216 }
217 
218 template <typename T, int N>
219 int
221 {
222 #ifdef DEBUG_RINGBUFFER
223  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
224 #endif
225 
226  return m_size - 1;
227 }
228 
229 template <typename T, int N>
231 RingBuffer<T, N>::resized(int newSize) const
232 {
233 #ifdef DEBUG_RINGBUFFER
234  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resized(" << newSize << ")" << std::endl;
235 #endif
236 
237  RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
238 
239  int w = m_writer;
240  int r = m_readers[0];
241 
242  while (r != w) {
243  T value = m_buffer[r];
244  newBuffer->write(&value, 1);
245  if (++r == m_size) r = 0;
246  }
247 
248  return newBuffer;
249 }
250 
251 template <typename T, int N>
252 bool
254 {
255  if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
256  m_mlocked = true;
257  return true;
258 }
259 
260 template <typename T, int N>
261 void
263 {
264 #ifdef DEBUG_RINGBUFFER
265  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
266 #endif
267 
268  m_writer = 0;
269  for (int i = 0; i < N; ++i) m_readers[i] = 0;
270 }
271 
272 template <typename T, int N>
273 int
275 {
276  int writer = m_writer;
277  int reader = m_readers[R];
278  int space = 0;
279 
280  if (writer > reader) space = writer - reader;
281  else space = ((writer + m_size) - reader) % m_size;
282 
283 #ifdef DEBUG_RINGBUFFER
284  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
285 #endif
286 
287  return space;
288 }
289 
290 template <typename T, int N>
291 int
293 {
294  int space = 0;
295  for (int i = 0; i < N; ++i) {
296  int here = (m_readers[i] + m_size - m_writer - 1) % m_size;
297  if (i == 0 || here < space) space = here;
298  }
299 
300 #ifdef DEBUG_RINGBUFFER
301  int rs(getReadSpace()), rp(m_readers[0]);
302 
303  std::cerr << "RingBuffer: write space " << space << ", read space "
304  << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
305  std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
306 #endif
307 
308 #ifdef DEBUG_RINGBUFFER
309  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
310 #endif
311 
312  return space;
313 }
314 
315 template <typename T, int N>
316 int
317 RingBuffer<T, N>::read(T *destination, int n, int R)
318 {
319 #ifdef DEBUG_RINGBUFFER
320  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
321 #endif
322 
323  int available = getReadSpace(R);
324  if (n > available) {
325 #ifdef DEBUG_RINGBUFFER
326  std::cerr << "WARNING: Only " << available << " samples available"
327  << std::endl;
328 #endif
329  memset(destination + available, 0, (n - available) * sizeof(T));
330  n = available;
331  }
332  if (n == 0) return n;
333 
334  int here = m_size - m_readers[R];
335  if (here >= n) {
336  memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
337  } else {
338  memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
339  memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
340  }
341 
342  MBARRIER();
343  m_readers[R] = (m_readers[R] + n) % m_size;
344 
345 #ifdef DEBUG_RINGBUFFER
346  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
347 #endif
348 
349  return n;
350 }
351 
352 template <typename T, int N>
353 int
354 RingBuffer<T, N>::readAdding(T *destination, int n, int R)
355 {
356 #ifdef DEBUG_RINGBUFFER
357  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
358 #endif
359 
360  int available = getReadSpace(R);
361  if (n > available) {
362 #ifdef DEBUG_RINGBUFFER
363  std::cerr << "WARNING: Only " << available << " samples available"
364  << std::endl;
365 #endif
366  n = available;
367  }
368  if (n == 0) return n;
369 
370  int here = m_size - m_readers[R];
371 
372  if (here >= n) {
373  for (int i = 0; i < n; ++i) {
374  destination[i] += (m_buffer + m_readers[R])[i];
375  }
376  } else {
377  for (int i = 0; i < here; ++i) {
378  destination[i] += (m_buffer + m_readers[R])[i];
379  }
380  for (int i = 0; i < (n - here); ++i) {
381  destination[i + here] += m_buffer[i];
382  }
383  }
384 
385  MBARRIER();
386  m_readers[R] = (m_readers[R] + n) % m_size;
387  return n;
388 }
389 
390 template <typename T, int N>
391 T
393 {
394 #ifdef DEBUG_RINGBUFFER
395  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
396 #endif
397 
398  if (m_writer == m_readers[R]) {
399 #ifdef DEBUG_RINGBUFFER
400  std::cerr << "WARNING: No sample available"
401  << std::endl;
402 #endif
403  T t;
404  memset(&t, 0, sizeof(T));
405  return t;
406  }
407  T value = m_buffer[m_readers[R]];
408  MBARRIER();
409  if (++m_readers[R] == m_size) m_readers[R] = 0;
410  return value;
411 }
412 
413 template <typename T, int N>
414 int
415 RingBuffer<T, N>::peek(T *destination, int n, int R) const
416 {
417 #ifdef DEBUG_RINGBUFFER
418  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
419 #endif
420 
421  int available = getReadSpace(R);
422  if (n > available) {
423 #ifdef DEBUG_RINGBUFFER
424  std::cerr << "WARNING: Only " << available << " samples available"
425  << std::endl;
426 #endif
427  memset(destination + available, 0, (n - available) * sizeof(T));
428  n = available;
429  }
430  if (n == 0) return n;
431 
432  int here = m_size - m_readers[R];
433  if (here >= n) {
434  memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
435  } else {
436  memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
437  memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
438  }
439 
440 #ifdef DEBUG_RINGBUFFER
441  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
442 #endif
443 
444  return n;
445 }
446 
447 template <typename T, int N>
448 T
450 {
451 #ifdef DEBUG_RINGBUFFER
452  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
453 #endif
454 
455  if (m_writer == m_readers[R]) {
456 #ifdef DEBUG_RINGBUFFER
457  std::cerr << "WARNING: No sample available"
458  << std::endl;
459 #endif
460  T t;
461  memset(&t, 0, sizeof(T));
462  return t;
463  }
464  T value = m_buffer[m_readers[R]];
465  return value;
466 }
467 
468 template <typename T, int N>
469 int
471 {
472 #ifdef DEBUG_RINGBUFFER
473  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
474 #endif
475 
476  int available = getReadSpace(R);
477  if (n > available) {
478 #ifdef DEBUG_RINGBUFFER
479  std::cerr << "WARNING: Only " << available << " samples available"
480  << std::endl;
481 #endif
482  n = available;
483  }
484  if (n == 0) return n;
485  m_readers[R] = (m_readers[R] + n) % m_size;
486  return n;
487 }
488 
489 template <typename T, int N>
490 int
491 RingBuffer<T, N>::write(const T *source, int n)
492 {
493 #ifdef DEBUG_RINGBUFFER
494  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
495 #endif
496 
497  int available = getWriteSpace();
498  if (n > available) {
499 #ifdef DEBUG_RINGBUFFER
500  std::cerr << "WARNING: Only room for " << available << " samples"
501  << std::endl;
502 #endif
503  n = available;
504  }
505  if (n == 0) return n;
506 
507  int here = m_size - m_writer;
508  if (here >= n) {
509  memcpy(m_buffer + m_writer, source, n * sizeof(T));
510  } else {
511  memcpy(m_buffer + m_writer, source, here * sizeof(T));
512  memcpy(m_buffer, source + here, (n - here) * sizeof(T));
513  }
514 
515  MBARRIER();
516  m_writer = (m_writer + n) % m_size;
517 
518 #ifdef DEBUG_RINGBUFFER
519  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
520 #endif
521 
522  return n;
523 }
524 
525 template <typename T, int N>
526 int
528 {
529 #ifdef DEBUG_RINGBUFFER
530  std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
531 #endif
532 
533  int available = getWriteSpace();
534  if (n > available) {
535 #ifdef DEBUG_RINGBUFFER
536  std::cerr << "WARNING: Only room for " << available << " samples"
537  << std::endl;
538 #endif
539  n = available;
540  }
541  if (n == 0) return n;
542 
543  int here = m_size - m_writer;
544  if (here >= n) {
545  memset(m_buffer + m_writer, 0, n * sizeof(T));
546  } else {
547  memset(m_buffer + m_writer, 0, here * sizeof(T));
548  memset(m_buffer, 0, (n - here) * sizeof(T));
549  }
550 
551  MBARRIER();
552  m_writer = (m_writer + n) % m_size;
553  return n;
554 }
555 
556 #endif // _RINGBUFFER_H_
RingBuffer & operator=(const RingBuffer &)
T peekOne(int R=0) const
Read one sample from the buffer, if available, without advancing the read pointer – i....
Definition: RingBuffer.h:449
bool m_mlocked
Definition: RingBuffer.h:167
int * m_readers
Definition: RingBuffer.h:169
T * m_buffer
Definition: RingBuffer.h:166
#define MUNLOCK(a, b)
Definition: System.h:80
T readOne(int R=0)
Read one sample from the buffer, for reader R.
Definition: RingBuffer.h:392
void reset()
Reset read and write pointers, thus emptying the buffer.
Definition: RingBuffer.h:262
int read(T *destination, int n, int R=0)
Read n samples from the buffer, for reader R.
Definition: RingBuffer.h:317
#define MBARRIER()
Definition: System.h:135
int peek(T *destination, int n, int R=0) const
Read n samples from the buffer, if available, for reader R, without advancing the read pointer – i....
Definition: RingBuffer.h:415
#define MLOCK(a, b)
Definition: System.h:79
int write(const T *source, int n)
Write n samples to the buffer.
Definition: RingBuffer.h:491
bool mlock()
Lock the ring buffer into physical memory.
Definition: RingBuffer.h:253
RingBuffer(int n)
Create a ring buffer with room to write n samples.
Definition: RingBuffer.h:179
virtual ~RingBuffer()
Definition: RingBuffer.h:204
RingBuffer implements a lock-free ring buffer for one writer and N readers, that is to be used to sto...
Definition: RingBuffer.h:46
int skip(int n, int R=0)
Pretend to read n samples from the buffer, for reader R, without actually returning them (i....
Definition: RingBuffer.h:470
int m_writer
Definition: RingBuffer.h:168
int getReadSpace(int R=0) const
Return the amount of data available for reading by reader R, in samples.
Definition: RingBuffer.h:274
int getWriteSpace() const
Return the amount of space available for writing, in samples.
Definition: RingBuffer.h:292
int readAdding(T *destination, int n, int R=0)
Read n samples from the buffer, for reader R, adding them to the destination.
Definition: RingBuffer.h:354
RingBuffer< T, N > * resized(int newSize) const
Return a new ring buffer (allocated with "new" – caller must delete when no longer needed) of the giv...
Definition: RingBuffer.h:231
int zero(int n)
Write n zero-value samples to the buffer.
Definition: RingBuffer.h:527
int getSize() const
Return the total capacity of the ring buffer in samples.
Definition: RingBuffer.h:220