fix up file renaming code a little bit
[ArdourMidi.git] / libs / rubberband / src / RingBuffer.h
blob07312169a6449c514a2c9a388cc917012d6384c6
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
3 /*
4 Rubber Band
5 An audio time-stretching and pitch-shifting library.
6 Copyright 2007-2008 Chris Cannam.
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.
15 #ifndef _RUBBERBAND_RINGBUFFER_H_
16 #define _RUBBERBAND_RINGBUFFER_H_
18 #include <cstring>
19 #include <sys/types.h>
21 #include <cstring>
23 #ifndef _WIN32
24 #include <sys/mman.h>
25 #endif
27 #include "Scavenger.h"
28 #include "Profiler.h"
31 //#define DEBUG_RINGBUFFER 1
33 #ifdef _WIN32
34 #define MLOCK(a,b) 1
35 #define MUNLOCK(a,b) 1
36 #else
37 #define MLOCK(a,b) ::mlock(a,b)
38 #define MUNLOCK(a,b) ::munlock(a,b)
39 #endif
41 #ifdef DEBUG_RINGBUFFER
42 #include <iostream>
43 #endif
45 namespace RubberBand {
47 /**
48 * RingBuffer implements a lock-free ring buffer for one writer and N
49 * readers, that is to be used to store a sample type T.
52 template <typename T, int N = 1>
53 class RingBuffer
55 public:
56 /**
57 * Create a ring buffer with room to write n samples.
59 * Note that the internal storage size will actually be n+1
60 * samples, as one element is unavailable for administrative
61 * reasons. Since the ring buffer performs best if its size is a
62 * power of two, this means n should ideally be some power of two
63 * minus one.
65 RingBuffer(int n);
67 virtual ~RingBuffer();
69 /**
70 * Return the total capacity of the ring buffer in samples.
71 * (This is the argument n passed to the constructor.)
73 int getSize() const;
75 /**
76 * Resize the ring buffer. This also empties it; use resized()
77 * below if you do not want this to happen. Actually swaps in a
78 * new, larger buffer; the old buffer is scavenged after a seemly
79 * delay. Should be called from the write thread.
81 void resize(int newSize);
83 /**
84 * Return a new ring buffer (allocated with "new" -- called must
85 * delete when no longer needed) of the given size, containing the
86 * same data as this one. If another thread reads from or writes
87 * to this buffer during the call, the results may be incomplete
88 * or inconsistent. If this buffer's data will not fit in the new
89 * size, the contents are undefined.
91 RingBuffer<T, N> *resized(int newSize, int R = 0) const;
93 /**
94 * Lock the ring buffer into physical memory. Returns true
95 * for success.
97 bool mlock();
99 /**
100 * Reset read and write pointers, thus emptying the buffer.
101 * Should be called from the write thread.
103 void reset();
106 * Return the amount of data available for reading by reader R, in
107 * samples.
109 int getReadSpace(int R = 0) const;
112 * Return the amount of space available for writing, in samples.
114 int getWriteSpace() const;
117 * Read n samples from the buffer, for reader R. If fewer than n
118 * are available, the remainder will be zeroed out. Returns the
119 * number of samples actually read.
121 int read(T *R__ destination, int n, int R = 0);
124 * Read n samples from the buffer, for reader R, adding them to
125 * the destination. If fewer than n are available, the remainder
126 * will be left alone. Returns the number of samples actually
127 * read.
129 int readAdding(T *R__ destination, int n, int R = 0);
132 * Read one sample from the buffer, for reader R. If no sample is
133 * available, this will silently return zero. Calling this
134 * repeatedly is obviously slower than calling read once, but it
135 * may be good enough if you don't want to allocate a buffer to
136 * read into.
138 T readOne(int R = 0);
141 * Read n samples from the buffer, if available, for reader R,
142 * without advancing the read pointer -- i.e. a subsequent read()
143 * or skip() will be necessary to empty the buffer. If fewer than
144 * n are available, the remainder will be zeroed out. Returns the
145 * number of samples actually read.
147 int peek(T *R__ destination, int n, int R = 0) const;
150 * Read one sample from the buffer, if available, without
151 * advancing the read pointer -- i.e. a subsequent read() or
152 * skip() will be necessary to empty the buffer. Returns zero if
153 * no sample was available.
155 T peekOne(int R = 0) const;
158 * Pretend to read n samples from the buffer, for reader R,
159 * without actually returning them (i.e. discard the next n
160 * samples). Returns the number of samples actually available for
161 * discarding.
163 int skip(int n, int R = 0);
166 * Write n samples to the buffer. If insufficient space is
167 * available, not all samples may actually be written. Returns
168 * the number of samples actually written.
170 int write(const T *source, int n);
173 * Write n zero-value samples to the buffer. If insufficient
174 * space is available, not all zeros may actually be written.
175 * Returns the number of zeroes actually written.
177 int zero(int n);
179 protected:
180 T *R__ m_buffer;
181 volatile int m_writer;
182 volatile int m_readers[N];
183 int m_size;
184 bool m_mlocked;
186 static Scavenger<ScavengerArrayWrapper<T> > m_scavenger;
188 private:
189 RingBuffer(const RingBuffer &); // not provided
190 RingBuffer &operator=(const RingBuffer &); // not provided
193 template <typename T, int N>
194 Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
196 template <typename T, int N>
197 RingBuffer<T, N>::RingBuffer(int n) :
198 m_buffer(new T[n + 1]),
199 m_writer(0),
200 m_size(n + 1),
201 m_mlocked(false)
203 #ifdef DEBUG_RINGBUFFER
204 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
205 #endif
207 for (int i = 0; i < N; ++i) m_readers[i] = 0;
209 m_scavenger.scavenge();
212 template <typename T, int N>
213 RingBuffer<T, N>::~RingBuffer()
215 #ifdef DEBUG_RINGBUFFER
216 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
217 #endif
219 if (m_mlocked) {
220 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
222 delete[] m_buffer;
224 m_scavenger.scavenge();
227 template <typename T, int N>
229 RingBuffer<T, N>::getSize() const
231 #ifdef DEBUG_RINGBUFFER
232 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
233 #endif
235 return m_size - 1;
238 template <typename T, int N>
239 void
240 RingBuffer<T, N>::resize(int newSize)
242 #ifdef DEBUG_RINGBUFFER
243 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl;
244 #endif
246 m_scavenger.scavenge();
248 if (m_mlocked) {
249 MUNLOCK((void *)m_buffer, m_size * sizeof(T));
252 m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer));
254 reset();
255 m_buffer = new T[newSize + 1];
256 m_size = newSize + 1;
258 if (m_mlocked) {
259 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) {
260 m_mlocked = false;
265 template <typename T, int N>
266 RingBuffer<T, N> *
267 RingBuffer<T, N>::resized(int newSize, int R) const
269 RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
271 int w = m_writer;
272 int r = m_readers[R];
274 while (r != w) {
275 T value = m_buffer[r];
276 newBuffer->write(&value, 1);
277 if (++r == m_size) r = 0;
280 return newBuffer;
283 template <typename T, int N>
284 bool
285 RingBuffer<T, N>::mlock()
287 if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
288 m_mlocked = true;
289 return true;
292 template <typename T, int N>
293 void
294 RingBuffer<T, N>::reset()
296 #ifdef DEBUG_RINGBUFFER
297 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
298 #endif
300 m_writer = 0;
301 for (int i = 0; i < N; ++i) m_readers[i] = 0;
304 template <typename T, int N>
306 RingBuffer<T, N>::getReadSpace(int R) const
308 int writer = m_writer;
309 int reader = m_readers[R];
310 int space;
312 #ifdef DEBUG_RINGBUFFER
313 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): reader " << reader << ", writer " << writer << std::endl;
314 #endif
316 if (writer > reader) space = writer - reader;
317 else if (writer < reader) space = (writer + m_size) - reader;
318 else space = 0;
320 #ifdef DEBUG_RINGBUFFER
321 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
322 #endif
324 return space;
327 template <typename T, int N>
329 RingBuffer<T, N>::getWriteSpace() const
331 int space = 0;
332 for (int i = 0; i < N; ++i) {
333 int writer = m_writer;
334 int reader = m_readers[i];
335 int here = (reader + m_size - writer - 1);
336 if (here >= m_size) here -= m_size;
337 if (i == 0 || here < space) space = here;
340 #ifdef DEBUG_RINGBUFFER
341 int rs(getReadSpace()), rp(m_readers[0]);
343 std::cerr << "RingBuffer: write space " << space << ", read space "
344 << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
345 std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
346 #endif
348 #ifdef DEBUG_RINGBUFFER
349 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
350 #endif
352 return space;
355 template <typename T, int N>
357 RingBuffer<T, N>::read(T *R__ destination, int n, int R)
359 Profiler profiler("RingBuffer::read");
361 #ifdef DEBUG_RINGBUFFER
362 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
363 #endif
365 int available = getReadSpace(R);
366 if (n > available) {
367 #ifdef DEBUG_RINGBUFFER
368 std::cerr << "WARNING: Only " << available << " samples available"
369 << std::endl;
370 #endif
371 for (int i = available; i < n; ++i) {
372 destination[i] = 0;
374 n = available;
376 if (n == 0) return n;
378 int reader = m_readers[R];
379 int here = m_size - reader;
380 T *const R__ bufbase = m_buffer + reader;
382 if (here >= n) {
383 for (int i = 0; i < n; ++i) {
384 destination[i] = bufbase[i];
386 } else {
387 for (int i = 0; i < here; ++i) {
388 destination[i] = bufbase[i];
390 T *const R__ destbase = destination + here;
391 const int nh = n - here;
392 for (int i = 0; i < nh; ++i) {
393 destbase[i] = m_buffer[i];
397 reader += n;
398 while (reader >= m_size) reader -= m_size;
399 m_readers[R] = reader;
401 #ifdef DEBUG_RINGBUFFER
402 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
403 #endif
405 return n;
408 template <typename T, int N>
410 RingBuffer<T, N>::readAdding(T *R__ destination, int n, int R)
412 Profiler profiler("RingBuffer::readAdding");
414 #ifdef DEBUG_RINGBUFFER
415 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
416 #endif
418 int available = getReadSpace(R);
419 if (n > available) {
420 #ifdef DEBUG_RINGBUFFER
421 std::cerr << "WARNING: Only " << available << " samples available"
422 << std::endl;
423 #endif
424 n = available;
426 if (n == 0) return n;
428 int reader = m_readers[R];
429 int here = m_size - reader;
430 const T *const R__ bufbase = m_buffer + reader;
432 if (here >= n) {
433 for (int i = 0; i < n; ++i) {
434 destination[i] += bufbase[i];
436 } else {
437 for (int i = 0; i < here; ++i) {
438 destination[i] += bufbase[i];
440 T *const R__ destbase = destination + here;
441 const int nh = n - here;
442 for (int i = 0; i < nh; ++i) {
443 destbase[i] += m_buffer[i];
447 reader += n;
448 while (reader >= m_size) reader -= m_size;
449 m_readers[R] = reader;
450 return n;
453 template <typename T, int N>
455 RingBuffer<T, N>::readOne(int R)
457 #ifdef DEBUG_RINGBUFFER
458 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
459 #endif
461 if (m_writer == m_readers[R]) {
462 #ifdef DEBUG_RINGBUFFER
463 std::cerr << "WARNING: No sample available"
464 << std::endl;
465 #endif
466 return 0;
468 int reader = m_readers[R];
469 T value = m_buffer[reader];
470 if (++reader == m_size) reader = 0;
471 m_readers[R] = reader;
472 return value;
475 template <typename T, int N>
477 RingBuffer<T, N>::peek(T *R__ destination, int n, int R) const
479 Profiler profiler("RingBuffer::peek");
481 #ifdef DEBUG_RINGBUFFER
482 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
483 #endif
485 int available = getReadSpace(R);
486 if (n > available) {
487 #ifdef DEBUG_RINGBUFFER
488 std::cerr << "WARNING: Only " << available << " samples available"
489 << std::endl;
490 #endif
491 memset(destination + available, 0, (n - available) * sizeof(T));
492 n = available;
494 if (n == 0) return n;
496 int reader = m_readers[R];
497 int here = m_size - reader;
498 const T *const R__ bufbase = m_buffer + reader;
500 if (here >= n) {
501 for (int i = 0; i < n; ++i) {
502 destination[i] = bufbase[i];
504 } else {
505 for (int i = 0; i < here; ++i) {
506 destination[i] = bufbase[i];
508 T *const R__ destbase = destination + here;
509 const int nh = n - here;
510 for (int i = 0; i < nh; ++i) {
511 destbase[i] = m_buffer[i];
515 #ifdef DEBUG_RINGBUFFER
516 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
517 #endif
519 return n;
522 template <typename T, int N>
524 RingBuffer<T, N>::peekOne(int R) const
526 #ifdef DEBUG_RINGBUFFER
527 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
528 #endif
530 if (m_writer == m_readers[R]) {
531 #ifdef DEBUG_RINGBUFFER
532 std::cerr << "WARNING: No sample available"
533 << std::endl;
534 #endif
535 return 0;
537 T value = m_buffer[m_readers[R]];
538 return value;
541 template <typename T, int N>
543 RingBuffer<T, N>::skip(int n, int R)
545 #ifdef DEBUG_RINGBUFFER
546 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
547 #endif
549 int available = getReadSpace(R);
550 if (n > available) {
551 #ifdef DEBUG_RINGBUFFER
552 std::cerr << "WARNING: Only " << available << " samples available"
553 << std::endl;
554 #endif
555 n = available;
557 if (n == 0) return n;
559 int reader = m_readers[R];
560 reader += n;
561 while (reader >= m_size) reader -= m_size;
562 m_readers[R] = reader;
563 return n;
566 template <typename T, int N>
568 RingBuffer<T, N>::write(const T *source, int n)
570 Profiler profiler("RingBuffer::write");
572 #ifdef DEBUG_RINGBUFFER
573 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
574 #endif
576 int available = getWriteSpace();
577 if (n > available) {
578 #ifdef DEBUG_RINGBUFFER
579 std::cerr << "WARNING: Only room for " << available << " samples"
580 << std::endl;
581 #endif
582 n = available;
584 if (n == 0) return n;
586 int writer = m_writer;
587 int here = m_size - writer;
588 T *const R__ bufbase = m_buffer + writer;
590 if (here >= n) {
591 for (int i = 0; i < n; ++i) {
592 bufbase[i] = source[i];
594 } else {
595 for (int i = 0; i < here; ++i) {
596 bufbase[i] = source[i];
598 const int nh = n - here;
599 const T *const R__ srcbase = source + here;
600 T *const R__ buf = m_buffer;
601 for (int i = 0; i < nh; ++i) {
602 buf[i] = srcbase[i];
606 writer += n;
607 while (writer >= m_size) writer -= m_size;
608 m_writer = writer;
610 #ifdef DEBUG_RINGBUFFER
611 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
612 #endif
614 return n;
617 template <typename T, int N>
619 RingBuffer<T, N>::zero(int n)
621 Profiler profiler("RingBuffer::zero");
623 #ifdef DEBUG_RINGBUFFER
624 std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
625 #endif
627 int available = getWriteSpace();
628 if (n > available) {
629 #ifdef DEBUG_RINGBUFFER
630 std::cerr << "WARNING: Only room for " << available << " samples"
631 << std::endl;
632 #endif
633 n = available;
635 if (n == 0) return n;
637 int writer = m_writer;
638 int here = m_size - writer;
639 T *const R__ bufbase = m_buffer + writer;
641 if (here >= n) {
642 for (int i = 0; i < n; ++i) {
643 bufbase[i] = 0;
645 } else {
646 for (int i = 0; i < here; ++i) {
647 bufbase[i] = 0;
649 const int nh = n - here;
650 for (int i = 0; i < nh; ++i) {
651 m_buffer[i] = 0;
655 writer += n;
656 while (writer >= m_size) writer -= m_size;
657 m_writer = writer;
659 #ifdef DEBUG_RINGBUFFER
660 std::cerr << "writer -> " << m_writer << std::endl;
661 #endif
663 return n;
668 //#include "RingBuffer.cpp"
670 #endif // _RINGBUFFER_H_