|
libpsynth 0.2.1
|
00001 00018 /* 00019 * Copyright (C) 2010 Juan Pedro Bolivar Puente 00020 * 00021 * This file is part of Psychosynth. 00022 * 00023 * Psychosynth is free software: you can redistribute it and/or modify 00024 * it under the terms of the GNU General Public License as published by 00025 * the Free Software Foundation, either version 3 of the License, or 00026 * (at your option) any later version. 00027 * 00028 * Psychosynth is distributed in the hope that it will be useful, 00029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00031 * GNU General Public License for more details. 00032 * 00033 * You should have received a copy of the GNU General Public License 00034 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00035 * 00036 */ 00037 00038 #ifndef PSYNTH_SOUND_RING_BUFFER_RANGE_H_ 00039 #define PSYNTH_SOUND_RING_BUFFER_RANGE_H_ 00040 00041 #include <boost/iterator/iterator_traits.hpp> 00042 #include <boost/iterator/iterator_facade.hpp> 00043 00044 #include <psynth/sound/metafunctions.hpp> 00045 #include <psynth/sound/buffer_range.hpp> 00046 00047 namespace psynth 00048 { 00049 namespace sound 00050 { 00051 00052 class default_channel_converter; 00053 00057 enum class ring_buffer_error 00058 { 00060 none, 00061 00067 underrun, 00068 00073 overrun 00074 }; 00075 00076 namespace detail 00077 { 00078 00082 template <class Ring> 00083 class unsafe_ring_position 00084 { 00085 public: 00086 typedef typename Ring::size_type size_type; 00087 typedef typename Ring::difference_type difference_type; 00088 typedef Ring ring_type; 00089 00090 unsafe_ring_position () = default; 00091 unsafe_ring_position (const unsafe_ring_position& r) = default; 00092 unsafe_ring_position& operator= (const unsafe_ring_position& p) = default; 00093 00094 explicit unsafe_ring_position (size_type p) : _pos (p) {} 00095 00096 size_type offset () const 00097 { return _pos; } 00098 00099 bool operator== (const unsafe_ring_position& p) const 00100 { return _pos == p._pos; } 00101 00102 // TODO: Make private 00103 void _add (difference_type n) {} 00104 00105 size_type _pos; 00106 }; 00107 00108 template <class Ring> 00109 class ring_position : public unsafe_ring_position<Ring> 00110 { 00111 typedef unsafe_ring_position<Ring> parent_type; 00112 00113 public: 00114 typedef typename parent_type::size_type size_type; 00115 typedef typename parent_type::difference_type difference_type; 00116 00117 ring_position () = default; 00118 ring_position (const ring_position& r) = default; 00119 ring_position& operator= (const ring_position& p) = default; 00120 00121 explicit ring_position (size_type p, size_type c) 00122 : parent_type (p), _count (c) {} 00123 00124 difference_type count () const { return _count; } 00125 00126 bool operator== (const ring_position& p) const 00127 { return parent_type::operator== (p) && _count == p._count; } 00128 00129 // TODO: Make private 00130 void _add (difference_type n) 00131 { _count += n; } 00132 00133 difference_type _count; 00134 }; 00135 00136 template <class Position, class Ring> 00137 class ring_iterator : public boost::iterator_facade< 00138 ring_iterator<Position, Ring>, 00139 typename std::iterator_traits< 00140 typename Position::ring_type::range::iterator>::value_type, 00141 std::random_access_iterator_tag, 00142 typename std::iterator_traits< 00143 typename Position::ring_type::range::iterator>::reference, 00144 typename std::iterator_traits< 00145 typename Position::ring_type::range::iterator>::difference_type 00146 > 00147 { 00148 public: 00149 typedef Position position_type; 00150 typedef Ring ring_type; 00151 00152 ring_iterator () {} 00153 00154 ring_iterator (const Position& pos, const ring_type* ring) 00155 : _position (pos) 00156 , _ring (ring) 00157 {} 00158 00159 ring_iterator (const ring_iterator& it) 00160 : _position (it._position) 00161 , _ring (it._ring) 00162 {} 00163 00164 template <typename RingIterator> 00165 ring_iterator (const RingIterator& it) 00166 : _position (it._position) 00167 , _ring (it._ring) 00168 {} 00169 00170 ring_iterator& operator= (const ring_iterator& it) 00171 { 00172 _position = it._position; 00173 _ring = it._ring; 00174 return *this; 00175 } 00176 00177 template <typename RingIterator> 00178 ring_iterator& operator= (const RingIterator& it) 00179 { 00180 _position = it._position; 00181 _ring = it._ring; 00182 return *this; 00183 } 00184 00185 const position_type& position () 00186 { return _position; } 00187 00188 private: 00189 void increment () 00190 { _ring->increment (_position); } 00191 00192 void decrement () 00193 { _ring->decrement (_position); } 00194 00195 void advance (typename std::iterator_traits<ring_iterator>::difference_type n) 00196 { _ring->advance (_position, n); } 00197 00198 typename std::iterator_traits<ring_iterator>::reference dereference () const 00199 { return (*_ring) [_position._pos]; } 00200 00201 template <class RingIterator> 00202 typename std::iterator_traits<ring_iterator>::difference_type distance_to ( 00203 const RingIterator& it) const 00204 { return _ring->distance (_position, it._position); }; 00205 00206 template <typename RingIterator> 00207 bool equal (const RingIterator& it) const 00208 { return _position == it._position && _ring == it._ring; }; 00209 // TODO: Remove comparison of _ring? 00210 00211 friend class boost::iterator_core_access; 00212 position_type _position; 00213 const ring_type* _ring; 00214 }; 00215 00216 } /* namespace detail */ 00217 00221 template <typename Range> 00222 class ring_buffer_range_base 00223 { 00224 public: 00225 typedef Range range; 00226 00227 typedef typename Range::size_type size_type; 00228 typedef typename Range::difference_type difference_type; 00229 00230 typedef detail::unsafe_ring_position<ring_buffer_range_base> unsafe_position; 00231 typedef detail::ring_position<ring_buffer_range_base> position; 00232 00237 ring_buffer_range_base () 00238 : _backwards (false) 00239 , _startpos (0) 00240 , _writepos (0, 0) 00241 {} 00242 00244 ring_buffer_range_base (const ring_buffer_range_base& range) 00245 : _backwards (range._backwards) 00246 , _startpos (0) 00247 , _writepos (range._writepos) 00248 , _range (range._range) 00249 {} 00250 00251 explicit ring_buffer_range_base (const Range& range) 00252 : _backwards (false) 00253 , _startpos (0) 00254 , _writepos (0, 0) 00255 , _range (range) 00256 {} 00257 00258 #if 0 00259 // FIXME: This kind of constructor in this and related classes 00260 // produced anoying behaviour because the derived class does not 00261 // get casted and passes up through this constructor. 00262 00263 template<class Range2> 00264 explicit ring_buffer_range_base (Range2& range) 00265 : _backwards (false) 00266 , _startpos (0) 00267 , _writepos (0, 0) 00268 , _range (range) 00269 {} 00270 00271 template<class Range2> 00272 explicit ring_buffer_range_base (const Range2& range) 00273 : _backwards (false) 00274 , _startpos (0) 00275 , _writepos (0, 0) 00276 , _range (range) 00277 {} 00278 #endif 00279 00281 template <class Range2> 00282 ring_buffer_range_base (const ring_buffer_range_base<Range2>& range) 00283 : _backwards (range._backwards) 00284 , _startpos (0) 00285 , _writepos (range._writepos) 00286 , _range (range._range) 00287 {} 00288 00290 ring_buffer_range_base& operator= (const ring_buffer_range_base& range) 00291 { 00292 _backwards = range._backwards; 00293 _startpos = range._startpos; 00294 _writepos = range._writepos; 00295 return *this; 00296 } 00297 00301 size_type size () const 00302 { return _range.size (); } 00303 00307 unsafe_position begin_unsafe_pos () const 00308 { return unsafe_position (_startpos); }; 00309 00313 unsafe_position end_unsafe_pos () const 00314 { return unsafe_position (_writepos); }; 00315 00319 position begin_pos () const 00320 { 00321 return _writepos._count > (difference_type) size () ? 00322 position (_writepos._pos, _writepos._count - size ()) : 00323 position (_startpos, 0); 00324 }; 00325 00329 position end_pos () const 00330 { return _writepos; }; 00331 00336 size_type available (const position& r) const 00337 { return _writepos._count - r._count; } 00338 00343 size_type available (const unsafe_position& r) const 00344 { 00345 return _writepos._pos > r._pos ? 00346 _writepos._pos - r._pos : 00347 _writepos._pos + size () - r._pos; 00348 } 00349 00354 size_type available () const 00355 { return _writepos._count > size () ? size () : _writepos._count; } 00356 00360 int check_position (const position& reader) const 00361 { 00362 if (reader._count < _writepos._count - size ()) 00363 return ring_buffer_error::underrun; 00364 if (reader._count > _writepos._count) 00365 return ring_buffer_error::overrun; 00366 return ring_buffer_error::none; 00367 } 00368 00369 template <class Position> 00370 typename buffer_range_type<Range>::type 00371 sub_buffer_one (const Position& p, size_type slice) const; 00372 00373 template <class Position> 00374 typename buffer_range_type<Range>::type 00375 sub_buffer_two (const Position& p, size_type slice) const; 00376 00382 template<class Position, class Range2> 00383 size_t read (Position& r, const Range2& range) const 00384 { 00385 return read (r, range, range.size ()); 00386 }; 00387 00394 template<class Position, class Range2> 00395 size_type read (Position& r, const Range2& range, size_type samples) const; 00396 00402 template<class Position, class Range2, class CC = default_channel_converter> 00403 size_t read_and_convert (Position& r, const Range2& range, CC cc = CC ()) const 00404 { 00405 return read_and_convert (r, range, range.size (), cc); 00406 }; 00407 00414 template<class Position, class Range2, class CC = default_channel_converter> 00415 size_type read_and_convert (Position& r, const Range2& range, 00416 size_type samples, CC cc = CC ()) const; 00417 00422 template <class Range2> 00423 void write (const Range2& range) 00424 { 00425 write (range, range.size ()); 00426 } 00427 00433 template <class Range2> 00434 void write (const Range2& range, size_type samples); 00435 00440 template <class Range2, class CC = default_channel_converter> 00441 void write_and_convert (const Range2& range, CC cc = CC ()) 00442 { 00443 write_and_convert (range, range.size (), cc); 00444 } 00445 00451 template <class Range2, class CC = default_channel_converter> 00452 void write_and_convert (const Range2& range, size_type samples, 00453 CC cc = CC ()); 00454 00458 void zero () 00459 { 00460 fill_frames (_range, 0); // TODO: USE SAMPLE TRAITS 00461 } 00462 00466 bool is_backwards () const 00467 { return _backwards; } 00468 00483 void set_backwards () 00484 { 00485 _backwards = !_backwards; 00486 if (_writepos._count < size ()) 00487 std::swap (_startpos, _writepos._pos); 00488 } 00489 00494 void advance (difference_type n) 00495 { 00496 advance (_writepos, n); 00497 } 00498 00504 template <typename Position> // Models PositionConcept 00505 void advance (Position& r, difference_type n) const 00506 { 00507 difference_type new_pos = r._pos + n; 00508 if (n >= 0) 00509 while (new_pos >= difference_type (size ())) 00510 new_pos -= size (); 00511 else 00512 while (new_pos < 0) 00513 new_pos += size (); 00514 r._pos = new_pos; 00515 r._add (n * (is_backwards () ? -1 : 1)); 00516 } 00517 00518 difference_type distance (const unsafe_position& ra, 00519 const unsafe_position& rb) const 00520 { 00521 assert (false); // TODO 00522 } 00523 00524 difference_type distance (const position& ra, const position& rb) const 00525 { return rb.count () - ra.count (); } 00526 00527 template <typename Position> 00528 void increment (Position& r) const 00529 { 00530 ++ r._pos; 00531 if (r._pos == _range.size ()) 00532 r._pos = 0; 00533 r._add (1); 00534 } 00535 00536 template <typename Position> 00537 void decrement (Position& r) const 00538 { 00539 -- r._pos; 00540 if (r._pos < 0) 00541 r._pos = _range.size () - 1; 00542 r._add (-1); 00543 } 00544 00545 difference_type count () const 00546 { 00547 return _writepos.count (); 00548 } 00549 00557 position sync (const position& r) const 00558 { 00559 if (!_backwards) 00560 return position ( 00561 r._pos, _writepos._count - (r._pos <= _writepos._pos ? 00562 _writepos._pos - r._pos : 00563 size () - r._pos + _writepos._pos)); 00564 else 00565 return position ( 00566 r._pos, _writepos._count - (r._pos >= _writepos._pos ? 00567 r._pos - _writepos._pos : 00568 size () - _writepos._pos + r._pos)); 00569 } 00570 00571 public: 00572 bool _backwards; 00574 size_type _startpos; 00576 position _writepos; 00577 Range _range; 00578 }; 00579 00580 template <class Range> 00581 class ring_buffer_range : public ring_buffer_range_base<Range> 00582 { 00583 typedef ring_buffer_range_base<Range> parent_type; 00584 00585 public: 00586 typedef typename parent_type::range::value_type value_type; 00587 typedef typename parent_type::range::reference reference; 00588 typedef typename parent_type::range::difference_type difference_type; 00589 00590 typedef detail::ring_iterator<typename parent_type::unsafe_position, 00591 ring_buffer_range> 00592 unsafe_iterator; 00593 typedef detail::ring_iterator<typename parent_type::position, 00594 ring_buffer_range> 00595 iterator; 00596 00597 ring_buffer_range () = default; 00598 ring_buffer_range (const ring_buffer_range&) = default; 00599 ring_buffer_range& operator= (const ring_buffer_range&) = default; 00600 00601 explicit ring_buffer_range (const Range& range) 00602 : parent_type (range) 00603 {} 00604 00605 #if 0 00606 template<class Range2> 00607 explicit ring_buffer_range (Range2& range) 00608 : parent_type (range) {} 00609 00610 template<class Range2> 00611 explicit ring_buffer_range (const Range2& range) 00612 : parent_type (range) {} 00613 00614 00616 template <class Range2> 00617 ring_buffer_range (const ring_buffer_range<Range2>& range) 00618 : parent_type ((const ring_buffer_range_base<Range2>&) range) {} 00619 #endif 00620 00621 unsafe_iterator begin_unsafe () const 00622 { return unsafe_iterator (this->begin_unsafe_pos (), this); } 00623 00624 unsafe_iterator end_unsafe () const 00625 { return unsafe_iterator (this->end_unsafe_pos (), this); } 00626 00627 iterator begin () const 00628 { return iterator (this->begin_pos (), this); } 00629 00630 iterator end () const 00631 { return iterator (this->end_pos (), this); } 00632 00636 reference operator [] (difference_type i) const 00637 { return this->_range [i]; } // potential performance problem! 00638 00639 iterator at (difference_type i) const 00640 { return begin () + i; } 00641 00642 unsafe_iterator unsafe_at (difference_type i) const 00643 { return begin_unsafe () + i; } 00644 }; 00645 00646 template <class Range> 00647 struct const_ring_buffer_range : 00648 public ring_buffer_range<typename Range::const_type> {}; 00649 00650 /* 00651 * 00652 * @todo FrameBasedConcept 00653 * 00654 */ 00655 00656 template <typename Range> 00657 struct sample_type<ring_buffer_range<Range> > : 00658 public sample_type<Range> {}; 00659 00660 template <typename Range> 00661 struct channel_space_type<ring_buffer_range<Range> > : 00662 public channel_space_type<Range> {}; 00663 00664 template <typename Range> 00665 struct sample_mapping_type<ring_buffer_range<Range> > : 00666 public sample_mapping_type<Range> {}; 00667 00668 template <typename Range> 00669 struct is_planar<ring_buffer_range<Range> > : 00670 public is_planar<Range> {}; 00671 00672 /* 00673 * 00674 * @todo DynamicStepTypeConcept 00675 * 00676 */ 00677 00678 00679 } /* namespace sound */ 00680 } /* namespace psynth */ 00681 00682 #include <psynth/sound/ring_buffer_range.tpp> 00683 00684 #endif /* PSYNTH_SOUND_RING_BUFFER_RANGE_H_ */ 00685
1.7.4