svcore  1.9
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 
00028 #include <cstring> // memcpy, memset &c
00029 
00030 //#define DEBUG_RINGBUFFER 1
00031 
00032 #ifdef DEBUG_RINGBUFFER
00033 #include <iostream>
00034 #endif
00035 
00045 template <typename T, int N = 1>
00046 class RingBuffer
00047 {
00048 public:
00058     RingBuffer(int n);
00059 
00060     virtual ~RingBuffer();
00061 
00066     int getSize() const;
00067 
00077     RingBuffer<T, N> *resized(int newSize) const;
00078 
00083     bool mlock();
00084 
00089     void reset();
00090 
00095     int getReadSpace(int R = 0) const;
00096 
00100     int getWriteSpace() const;
00101 
00107     int read(T *destination, int n, int R = 0);
00108 
00115     int readAdding(T *destination, int n, int R = 0);
00116 
00124     T readOne(int R = 0);
00125 
00133     int peek(T *destination, int n, int R = 0) const;
00134 
00141     T peekOne(int R = 0) const;
00142 
00149     int skip(int n, int R = 0);
00150 
00156     int write(const T *source, int n);
00157 
00163     int zero(int n);
00164 
00165 protected:
00166     T   *m_buffer;
00167     bool m_mlocked;
00168     int  m_writer;
00169     int *m_readers;
00170     int  m_size;
00171     int  m_spare;
00172 
00173 private:
00174     RingBuffer(const RingBuffer &); // not provided
00175     RingBuffer &operator=(const RingBuffer &); // not provided
00176 };
00177 
00178 template <typename T, int N>
00179 RingBuffer<T, N>::RingBuffer(int n) :
00180     m_buffer(new T[n + 1]),
00181     m_mlocked(false),
00182     m_writer(0),
00183     m_readers(new int[N]),
00184     m_size(n + 1)
00185 {
00186 #ifdef DEBUG_RINGBUFFER
00187     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::RingBuffer(" << n << ")" << std::endl;
00188 #endif
00189 /*
00190     std::cerr << "note: sizeof(RingBuffer<T,N> = " << sizeof(RingBuffer<T,N>) << ")" << std::endl;
00191 
00192     std::cerr << "this = " << this << std::endl;
00193     std::cerr << "&m_buffer = " << &m_buffer << std::endl;
00194     std::cerr << "&m_mlocked = " << &m_mlocked << std::endl;
00195     std::cerr << "&m_writer = " << &m_writer << std::endl;
00196     std::cerr << "&m_readers = " << &m_readers << std::endl;
00197     std::cerr << "&m_size = " << &m_size << std::endl;
00198 */
00199     
00200     for (int i = 0; i < N; ++i) m_readers[i] = 0;
00201 }
00202 
00203 template <typename T, int N>
00204 RingBuffer<T, N>::~RingBuffer()
00205 {
00206 #ifdef DEBUG_RINGBUFFER
00207     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::~RingBuffer" << std::endl;
00208 #endif
00209 
00210     delete[] m_readers;
00211 
00212     if (m_mlocked) {
00213         MUNLOCK((void *)m_buffer, m_size * sizeof(T));
00214     }
00215     delete[] m_buffer;
00216 }
00217 
00218 template <typename T, int N>
00219 int
00220 RingBuffer<T, N>::getSize() const
00221 {
00222 #ifdef DEBUG_RINGBUFFER
00223     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getSize(): " << m_size-1 << std::endl;
00224 #endif
00225 
00226     return m_size - 1;
00227 }
00228 
00229 template <typename T, int N>
00230 RingBuffer<T, N> *
00231 RingBuffer<T, N>::resized(int newSize) const
00232 {
00233 #ifdef DEBUG_RINGBUFFER
00234     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::resized(" << newSize << ")" << std::endl;
00235 #endif
00236 
00237     RingBuffer<T, N> *newBuffer = new RingBuffer<T, N>(newSize);
00238 
00239     int w = m_writer;
00240     int r = m_readers[0];
00241 
00242     while (r != w) {
00243         T value = m_buffer[r];
00244         newBuffer->write(&value, 1);
00245         if (++r == m_size) r = 0;
00246     }
00247 
00248     return newBuffer;
00249 }
00250 
00251 template <typename T, int N>
00252 bool
00253 RingBuffer<T, N>::mlock()
00254 {
00255     if (MLOCK((void *)m_buffer, m_size * sizeof(T))) return false;
00256     m_mlocked = true;
00257     return true;
00258 }
00259 
00260 template <typename T, int N>
00261 void
00262 RingBuffer<T, N>::reset()
00263 {
00264 #ifdef DEBUG_RINGBUFFER
00265     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::reset" << std::endl;
00266 #endif
00267 
00268     m_writer = 0;
00269     for (int i = 0; i < N; ++i) m_readers[i] = 0;
00270 }
00271 
00272 template <typename T, int N>
00273 int
00274 RingBuffer<T, N>::getReadSpace(int R) const
00275 {
00276     int writer = m_writer;
00277     int reader = m_readers[R];
00278     int space = 0;
00279 
00280     if (writer > reader) space = writer - reader;
00281     else space = ((writer + m_size) - reader) % m_size;
00282 
00283 #ifdef DEBUG_RINGBUFFER
00284     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getReadSpace(" << R << "): " << space << std::endl;
00285 #endif
00286 
00287     return space;
00288 }
00289 
00290 template <typename T, int N>
00291 int
00292 RingBuffer<T, N>::getWriteSpace() const
00293 {
00294     int space = 0;
00295     for (int i = 0; i < N; ++i) {
00296         int here = (m_readers[i] + m_size - m_writer - 1) % m_size;
00297         if (i == 0 || here < space) space = here;
00298     }
00299 
00300 #ifdef DEBUG_RINGBUFFER
00301     int rs(getReadSpace()), rp(m_readers[0]);
00302 
00303     std::cerr << "RingBuffer: write space " << space << ", read space "
00304               << rs << ", total " << (space + rs) << ", m_size " << m_size << std::endl;
00305     std::cerr << "RingBuffer: reader " << rp << ", writer " << m_writer << std::endl;
00306 #endif
00307 
00308 #ifdef DEBUG_RINGBUFFER
00309     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::getWriteSpace(): " << space << std::endl;
00310 #endif
00311 
00312     return space;
00313 }
00314 
00315 template <typename T, int N>
00316 int
00317 RingBuffer<T, N>::read(T *destination, int n, int R)
00318 {
00319 #ifdef DEBUG_RINGBUFFER
00320     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read(dest, " << n << ", " << R << ")" << std::endl;
00321 #endif
00322 
00323     int available = getReadSpace(R);
00324     if (n > available) {
00325 #ifdef DEBUG_RINGBUFFER
00326         std::cerr << "WARNING: Only " << available << " samples available"
00327                   << std::endl;
00328 #endif
00329         memset(destination + available, 0, (n - available) * sizeof(T));
00330         n = available;
00331     }
00332     if (n == 0) return n;
00333 
00334     int here = m_size - m_readers[R];
00335     if (here >= n) {
00336         memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
00337     } else {
00338         memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
00339         memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
00340     }
00341 
00342     MBARRIER();
00343     m_readers[R] = (m_readers[R] + n) % m_size;
00344 
00345 #ifdef DEBUG_RINGBUFFER
00346     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::read: read " << n << ", reader now " << m_readers[R] << std::endl;
00347 #endif
00348 
00349     return n;
00350 }
00351 
00352 template <typename T, int N>
00353 int
00354 RingBuffer<T, N>::readAdding(T *destination, int n, int R)
00355 {
00356 #ifdef DEBUG_RINGBUFFER
00357     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readAdding(dest, " << n << ", " << R << ")" << std::endl;
00358 #endif
00359 
00360     int available = getReadSpace(R);
00361     if (n > available) {
00362 #ifdef DEBUG_RINGBUFFER
00363         std::cerr << "WARNING: Only " << available << " samples available"
00364                   << std::endl;
00365 #endif
00366         n = available;
00367     }
00368     if (n == 0) return n;
00369 
00370     int here = m_size - m_readers[R];
00371 
00372     if (here >= n) {
00373         for (int i = 0; i < n; ++i) {
00374             destination[i] += (m_buffer + m_readers[R])[i];
00375         }
00376     } else {
00377         for (int i = 0; i < here; ++i) {
00378             destination[i] += (m_buffer + m_readers[R])[i];
00379         }
00380         for (int i = 0; i < (n - here); ++i) {
00381             destination[i + here] += m_buffer[i];
00382         }
00383     }
00384 
00385     MBARRIER();
00386     m_readers[R] = (m_readers[R] + n) % m_size;
00387     return n;
00388 }
00389 
00390 template <typename T, int N>
00391 T
00392 RingBuffer<T, N>::readOne(int R)
00393 {
00394 #ifdef DEBUG_RINGBUFFER
00395     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::readOne(" << R << ")" << std::endl;
00396 #endif
00397 
00398     if (m_writer == m_readers[R]) {
00399 #ifdef DEBUG_RINGBUFFER
00400         std::cerr << "WARNING: No sample available"
00401                   << std::endl;
00402 #endif
00403         T t;
00404         memset(&t, 0, sizeof(T));
00405         return t;
00406     }
00407     T value = m_buffer[m_readers[R]];
00408     MBARRIER();
00409     if (++m_readers[R] == m_size) m_readers[R] = 0;
00410     return value;
00411 }
00412 
00413 template <typename T, int N>
00414 int
00415 RingBuffer<T, N>::peek(T *destination, int n, int R) const
00416 {
00417 #ifdef DEBUG_RINGBUFFER
00418     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(dest, " << n << ", " << R << ")" << std::endl;
00419 #endif
00420 
00421     int available = getReadSpace(R);
00422     if (n > available) {
00423 #ifdef DEBUG_RINGBUFFER
00424         std::cerr << "WARNING: Only " << available << " samples available"
00425                   << std::endl;
00426 #endif
00427         memset(destination + available, 0, (n - available) * sizeof(T));
00428         n = available;
00429     }
00430     if (n == 0) return n;
00431 
00432     int here = m_size - m_readers[R];
00433     if (here >= n) {
00434         memcpy(destination, m_buffer + m_readers[R], n * sizeof(T));
00435     } else {
00436         memcpy(destination, m_buffer + m_readers[R], here * sizeof(T));
00437         memcpy(destination + here, m_buffer, (n - here) * sizeof(T));
00438     }
00439 
00440 #ifdef DEBUG_RINGBUFFER
00441     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek: read " << n << std::endl;
00442 #endif
00443 
00444     return n;
00445 }
00446 
00447 template <typename T, int N>
00448 T
00449 RingBuffer<T, N>::peekOne(int R) const
00450 {
00451 #ifdef DEBUG_RINGBUFFER
00452     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::peek(" << R << ")" << std::endl;
00453 #endif
00454 
00455     if (m_writer == m_readers[R]) {
00456 #ifdef DEBUG_RINGBUFFER
00457         std::cerr << "WARNING: No sample available"
00458                   << std::endl;
00459 #endif
00460         T t;
00461         memset(&t, 0, sizeof(T));
00462         return t;
00463     }
00464     T value = m_buffer[m_readers[R]];
00465     return value;
00466 }
00467 
00468 template <typename T, int N>
00469 int
00470 RingBuffer<T, N>::skip(int n, int R)
00471 {
00472 #ifdef DEBUG_RINGBUFFER
00473     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::skip(" << n << ", " << R << ")" << std::endl;
00474 #endif
00475 
00476     int available = getReadSpace(R);
00477     if (n > available) {
00478 #ifdef DEBUG_RINGBUFFER
00479         std::cerr << "WARNING: Only " << available << " samples available"
00480                   << std::endl;
00481 #endif
00482         n = available;
00483     }
00484     if (n == 0) return n;
00485     m_readers[R] = (m_readers[R] + n) % m_size;
00486     return n;
00487 }
00488 
00489 template <typename T, int N>
00490 int
00491 RingBuffer<T, N>::write(const T *source, int n)
00492 {
00493 #ifdef DEBUG_RINGBUFFER
00494     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write(" << n << ")" << std::endl;
00495 #endif
00496 
00497     int available = getWriteSpace();
00498     if (n > available) {
00499 #ifdef DEBUG_RINGBUFFER
00500         std::cerr << "WARNING: Only room for " << available << " samples"
00501                   << std::endl;
00502 #endif
00503         n = available;
00504     }
00505     if (n == 0) return n;
00506 
00507     int here = m_size - m_writer;
00508     if (here >= n) {
00509         memcpy(m_buffer + m_writer, source, n * sizeof(T));
00510     } else {
00511         memcpy(m_buffer + m_writer, source, here * sizeof(T));
00512         memcpy(m_buffer, source + here, (n - here) * sizeof(T));
00513     }
00514 
00515     MBARRIER();
00516     m_writer = (m_writer + n) % m_size;
00517 
00518 #ifdef DEBUG_RINGBUFFER
00519     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::write: wrote " << n << ", writer now " << m_writer << std::endl;
00520 #endif
00521 
00522     return n;
00523 }
00524 
00525 template <typename T, int N>
00526 int
00527 RingBuffer<T, N>::zero(int n)
00528 {
00529 #ifdef DEBUG_RINGBUFFER
00530     std::cerr << "RingBuffer<T," << N << ">[" << this << "]::zero(" << n << ")" << std::endl;
00531 #endif
00532 
00533     int available = getWriteSpace();
00534     if (n > available) {
00535 #ifdef DEBUG_RINGBUFFER
00536         std::cerr << "WARNING: Only room for " << available << " samples"
00537                   << std::endl;
00538 #endif
00539         n = available;
00540     }
00541     if (n == 0) return n;
00542 
00543     int here = m_size - m_writer;
00544     if (here >= n) {
00545         memset(m_buffer + m_writer, 0, n * sizeof(T));
00546     } else {
00547         memset(m_buffer + m_writer, 0, here * sizeof(T));
00548         memset(m_buffer, 0, (n - here) * sizeof(T));
00549     }
00550     
00551     MBARRIER();
00552     m_writer = (m_writer + n) % m_size;
00553     return n;
00554 }
00555 
00556 #endif // _RINGBUFFER_H_