libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/sound/ring_buffer_range.hpp
Go to the documentation of this file.
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