RingBuffer.h

Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     
00008     This program is free software; you can redistribute it and/or
00009     modify it under the terms of the GNU General Public License as
00010     published by the Free Software Foundation; either version 2 of the
00011     License, or (at your option) any later version.  See the file
00012     COPYING included with this distribution for more information.
00013 */
00014 
00015 /*
00016    This is a modified version of a source file from the 
00017    Rosegarden MIDI and audio sequencer and notation editor.
00018    This file copyright 2000-2006 Chris Cannam.
00019 */
00020 
00021 #ifndef _RINGBUFFER_H_
00022 #define _RINGBUFFER_H_
00023 
00024 #include <sys/types.h>
00025 
00026 #include "system/System.h"
00027 #include "Scavenger.h"
00028 
00029 //#define DEBUG_RINGBUFFER 1
00030 
00031 #ifdef DEBUG_RINGBUFFER
00032 #include <iostream>
00033 #endif
00034 
00044 template <typename T, int N = 1>
00045 class RingBuffer
00046 {
00047 public:
00057     RingBuffer(size_t n);
00058 
00059     virtual ~RingBuffer();
00060 
00065     size_t getSize() const;
00066 
00072     void resize(size_t newSize);
00073 
00078     bool mlock();
00079 
00084     void reset();
00085 
00090     size_t getReadSpace(int R = 0) const;
00091 
00095     size_t getWriteSpace() const;
00096 
00102     size_t read(T *destination, size_t n, int R = 0);
00103 
00110     size_t readAdding(T *destination, size_t n, int R = 0);
00111 
00119     T readOne(int R = 0);
00120 
00128     size_t peek(T *destination, size_t n, int R = 0) const;
00129 
00136     T peekOne(int R = 0) const;
00137 
00144     size_t skip(size_t n, int R = 0);
00145 
00151     size_t write(const T *source, size_t n);
00152 
00158     size_t zero(size_t n);
00159 
00160 protected:
00161     T               *m_buffer;
00162     volatile size_t  m_writer;
00163     volatile size_t  m_readers[N];
00164     size_t           m_size;
00165     bool             m_mlocked;
00166 
00167     static Scavenger<ScavengerArrayWrapper<T> > m_scavenger;
00168 
00169 private:
00170     RingBuffer(const RingBuffer &); // not provided
00171     RingBuffer &operator=(const RingBuffer &); // not provided
00172 };
00173 
00174 template <typename T, int N>
00175 Scavenger<ScavengerArrayWrapper<T> > RingBuffer<T, N>::m_scavenger;
00176 
00177 template <typename T, int N>
00178 RingBuffer<T, N>::RingBuffer(size_t n) :
00179     m_buffer(new T[n + 1]),
00180     m_writer(0),
00181     m_size(n + 1),
00182     m_mlocked(false)
00183 {
00184 #ifdef DEBUG_RINGBUFFER
00185     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
00186 #endif
00187 
00188     for (int i = 0; i < N; ++i) m_readers[i] = 0;
00189 
00190     m_scavenger.scavenge();
00191 }
00192 
00193 template <typename T, int N>
00194 RingBuffer<T, N>::~RingBuffer()
00195 {
00196 #ifdef DEBUG_RINGBUFFER
00197     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
00198 #endif
00199 
00200     if (m_mlocked) {
00201         MUNLOCK((void *)m_buffer, m_size * sizeof(T));
00202     }
00203     delete[] m_buffer;
00204 
00205     m_scavenger.scavenge();
00206 }
00207 
00208 template <typename T, int N>
00209 size_t
00210 RingBuffer<T, N>::getSize() const
00211 {
00212 #ifdef DEBUG_RINGBUFFER
00213     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
00214 #endif
00215 
00216     return m_size - 1;
00217 }
00218 
00219 template <typename T, int N>
00220 void
00221 RingBuffer<T, N>::resize(size_t newSize)
00222 {
00223 #ifdef DEBUG_RINGBUFFER
00224     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resize(" << newSize << ")" << std::endl;
00225 #endif
00226 
00227     m_scavenger.scavenge();
00228 
00229     if (m_mlocked) {
00230         MUNLOCK((void *)m_buffer, m_size * sizeof(T));
00231     }
00232 
00233     m_scavenger.claim(new ScavengerArrayWrapper<T>(m_buffer));
00234 
00235     reset();
00236     m_buffer = new T[newSize + 1];
00237     m_size = newSize + 1;
00238 
00239     if (m_mlocked) {
00240         if (MLOCK((void *)m_buffer, m_size * sizeof(T))) {
00241             m_mlocked = false;
00242         }
00243     }
00244 }
00245 
00246 template <typename T, int N>
00247 bool
00248 RingBuffer<T, N>::mlock()
00249 {
00250     if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
00251     m_mlocked = true;
00252     return true;
00253 }
00254 
00255 template <typename T, int N>
00256 void
00257 RingBuffer<T, N>::reset()
00258 {
00259 #ifdef DEBUG_RINGBUFFER
00260     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
00261 #endif
00262 
00263     m_writer = 0;
00264     for (int i = 0; i < N; ++i) m_readers[i] = 0;
00265 }
00266 
00267 template <typename T, int N>
00268 size_t
00269 RingBuffer<T, N>::getReadSpace(int R) const
00270 {
00271     size_t writer = m_writer;
00272     size_t reader = m_readers[R];
00273     size_t space = 0;
00274 
00275     if (writer > reader) space = writer - reader;
00276     else space = ((writer + m_size) - reader) % m_size;
00277 
00278 #ifdef DEBUG_RINGBUFFER
00279     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
00280 #endif
00281 
00282     return space;
00283 }
00284 
00285 template <typename T, int N>
00286 size_t
00287 RingBuffer<T, N>::getWriteSpace() const
00288 {
00289     size_t space = 0;
00290     for (int i = 0; i < N; ++i) {
00291         size_t here = (m_readers[i] + m_size - m_writer - 1) % m_size;
00292         if (i == 0 || here < space) space = here;
00293     }
00294 
00295 #ifdef DEBUG_RINGBUFFER
00296     size_t rs(getReadSpace()), rp(m_readers[0]);
00297 
00298     std::cerr << "RingBuffer: write space " << space << ", read space "
00299               << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
00300     std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
00301 #endif
00302 
00303 #ifdef DEBUG_RINGBUFFER
00304     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
00305 #endif
00306 
00307     return space;
00308 }
00309 
00310 template <typename T, int N>
00311 size_t
00312 RingBuffer<T, N>::read(T *destination, size_t n, int R)
00313 {
00314 #ifdef DEBUG_RINGBUFFER
00315     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
00316 #endif
00317 
00318     size_t available = getReadSpace(R);
00319     if (n > available) {
00320 #ifdef DEBUG_RINGBUFFER
00321         std::cerr << "WARNING: Only " << available << " samples available"
00322                   << std::endl;
00323 #endif
00324         memset(destination + available, 0, (n - available) * sizeof(T));
00325         n = available;
00326     }
00327     if (n == 0) return n;
00328 
00329     size_t here = m_size - m_readers[R];
00330     if (here >= n) {
00331         memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
00332     } else {
00333         memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
00334         memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
00335     }
00336 
00337     m_readers[R] = (m_readers[R] + n) % m_size;
00338 
00339 #ifdef DEBUG_RINGBUFFER
00340     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
00341 #endif
00342 
00343     return n;
00344 }
00345 
00346 template <typename T, int N>
00347 size_t
00348 RingBuffer<T, N>::readAdding(T *destination, size_t n, int R)
00349 {
00350 #ifdef DEBUG_RINGBUFFER
00351     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
00352 #endif
00353 
00354     size_t available = getReadSpace(R);
00355     if (n > available) {
00356 #ifdef DEBUG_RINGBUFFER
00357         std::cerr << "WARNING: Only " << available << " samples available"
00358                   << std::endl;
00359 #endif
00360         n = available;
00361     }
00362     if (n == 0) return n;
00363 
00364     size_t here = m_size - m_readers[R];
00365 
00366     if (here >= n) {
00367         for (size_t i = 0; i < n; ++i) {
00368             destination[i] += (m_buffer + m_readers[R])[i];
00369         }
00370     } else {
00371         for (size_t i = 0; i < here; ++i) {
00372             destination[i] += (m_buffer + m_readers[R])[i];
00373         }
00374         for (size_t i = 0; i < (n - here); ++i) {
00375             destination[i + here] += m_buffer[i];
00376         }
00377     }
00378 
00379     m_readers[R] = (m_readers[R] + n) % m_size;
00380     return n;
00381 }
00382 
00383 template <typename T, int N>
00384 T
00385 RingBuffer<T, N>::readOne(int R)
00386 {
00387 #ifdef DEBUG_RINGBUFFER
00388     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
00389 #endif
00390 
00391     if (m_writer == m_readers[R]) {
00392 #ifdef DEBUG_RINGBUFFER
00393         std::cerr << "WARNING: No sample available"
00394                   << std::endl;
00395 #endif
00396         T t;
00397         memset(&t, 0, sizeof(T));
00398         return t;
00399     }
00400     T value = m_buffer[m_readers[R]];
00401     if (++m_readers[R] == m_size) m_readers[R] = 0;
00402     return value;
00403 }
00404 
00405 template <typename T, int N>
00406 size_t
00407 RingBuffer<T, N>::peek(T *destination, size_t n, int R) const
00408 {
00409 #ifdef DEBUG_RINGBUFFER
00410     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
00411 #endif
00412 
00413     size_t available = getReadSpace(R);
00414     if (n > available) {
00415 #ifdef DEBUG_RINGBUFFER
00416         std::cerr << "WARNING: Only " << available << " samples available"
00417                   << std::endl;
00418 #endif
00419         memset(destination + available, 0, (n - available) * sizeof(T));
00420         n = available;
00421     }
00422     if (n == 0) return n;
00423 
00424     size_t here = m_size - m_readers[R];
00425     if (here >= n) {
00426         memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
00427     } else {
00428         memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
00429         memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
00430     }
00431 
00432 #ifdef DEBUG_RINGBUFFER
00433     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
00434 #endif
00435 
00436     return n;
00437 }
00438 
00439 template <typename T, int N>
00440 T
00441 RingBuffer<T, N>::peekOne(int R) const
00442 {
00443 #ifdef DEBUG_RINGBUFFER
00444     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
00445 #endif
00446 
00447     if (m_writer == m_readers[R]) {
00448 #ifdef DEBUG_RINGBUFFER
00449         std::cerr << "WARNING: No sample available"
00450                   << std::endl;
00451 #endif
00452         T t;
00453         memset(&t, 0, sizeof(T));
00454         return t;
00455     }
00456     T value = m_buffer[m_readers[R]];
00457     return value;
00458 }
00459 
00460 template <typename T, int N>
00461 size_t
00462 RingBuffer<T, N>::skip(size_t n, int R)
00463 {
00464 #ifdef DEBUG_RINGBUFFER
00465     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
00466 #endif
00467 
00468     size_t available = getReadSpace(R);
00469     if (n > available) {
00470 #ifdef DEBUG_RINGBUFFER
00471         std::cerr << "WARNING: Only " << available << " samples available"
00472                   << std::endl;
00473 #endif
00474         n = available;
00475     }
00476     if (n == 0) return n;
00477     m_readers[R] = (m_readers[R] + n) % m_size;
00478     return n;
00479 }
00480 
00481 template <typename T, int N>
00482 size_t
00483 RingBuffer<T, N>::write(const T *source, size_t n)
00484 {
00485 #ifdef DEBUG_RINGBUFFER
00486     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
00487 #endif
00488 
00489     size_t available = getWriteSpace();
00490     if (n > available) {
00491 #ifdef DEBUG_RINGBUFFER
00492         std::cerr << "WARNING: Only room for " << available << " samples"
00493                   << std::endl;
00494 #endif
00495         n = available;
00496     }
00497     if (n == 0) return n;
00498 
00499     size_t here = m_size - m_writer;
00500     if (here >= n) {
00501         memcpy(m_buffer + m_writer, source, n * sizeof(T));
00502     } else {
00503         memcpy(m_buffer + m_writer, source, here * sizeof(T));
00504         memcpy(m_buffer, source + here, (n - here) * sizeof(T));
00505     }
00506 
00507     m_writer = (m_writer + n) % m_size;
00508 
00509 #ifdef DEBUG_RINGBUFFER
00510     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
00511 #endif
00512 
00513     return n;
00514 }
00515 
00516 template <typename T, int N>
00517 size_t
00518 RingBuffer<T, N>::zero(size_t n)
00519 {
00520 #ifdef DEBUG_RINGBUFFER
00521     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
00522 #endif
00523 
00524     size_t available = getWriteSpace();
00525     if (n > available) {
00526 #ifdef DEBUG_RINGBUFFER
00527         std::cerr << "WARNING: Only room for " << available << " samples"
00528                   << std::endl;
00529 #endif
00530         n = available;
00531     }
00532     if (n == 0) return n;
00533 
00534     size_t here = m_size - m_writer;
00535     if (here >= n) {
00536         memset(m_buffer + m_writer, 0, n * sizeof(T));
00537     } else {
00538         memset(m_buffer + m_writer, 0, here * sizeof(T));
00539         memset(m_buffer, 0, (n - here) * sizeof(T));
00540     }
00541 
00542     m_writer = (m_writer + n) % m_size;
00543     return n;
00544 }
00545 
00546 #endif // _RINGBUFFER_H_

Generated on Wed Feb 20 15:45:27 2008 for SonicVisualiser by  doxygen 1.5.1