svcore
1.9
|
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_