libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/sound/buffer.hpp
Go to the documentation of this file.
00001 
00011 /*
00012  *  Copyright (C) 2010 Juan Pedro Bolivar Puente
00013  *
00014  *  This file is part of Psychosynth.
00015  *   
00016  *  Psychosynth is free software: you can redistribute it and/or modify
00017  *  it under the terms of the GNU General Public License as published by
00018  *  the Free Software Foundation, either version 3 of the License, or
00019  *  (at your option) any later version.
00020  *
00021  *  Psychosynth is distributed in the hope that it will be useful,
00022  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  *  GNU General Public License for more details.
00025  *
00026  *  You should have received a copy of the GNU General Public License
00027  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00028  *
00029  */
00030 
00031 /*
00032  *  Copyright 2005-2007 Adobe Systems Incorporated
00033  * 
00034  *  Use, modification and distribution are subject to the Boost
00035  *  Software License, Version 1.0. (See accompanying file
00036  *  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
00037  */
00038 
00039 #ifndef PSYNTH_SOUND_BUFFER_H
00040 #define PSYNTH_SOUND_BUFFER_H
00041 
00042 #include <cstddef>
00043 #include <memory>
00044 #include <psynth/base/compat.hpp>
00045 #include <psynth/sound/frame.hpp>
00046 #include <psynth/sound/buffer_range.hpp>
00047 #include <psynth/sound/metafunctions.hpp>
00048 #include <psynth/sound/algorithm.hpp>
00049 
00050 namespace psynth
00051 {
00052 namespace sound
00053 {
00054 
00055 //#ifdef _MSC_VER
00056 //#pragma warning(push)
00057 //#pragma warning(disable : 4244)
00058 // conversion from 'sound::buffer<V,Alloc>::size_type' to 'int', possible
00059 // loss of data (visual studio compiler doesn't realize that the two
00060 // types are the same)
00061 //#endif
00062 
00082 template <typename Frame,
00083           bool IsPlanar,
00084           typename Alloc = std::allocator<unsigned char> >    
00085 class buffer
00086 {
00087 public:
00088     typedef typename Alloc::template rebind<unsigned char>::other allocator_type;
00089 
00090     typedef typename range_type_from_frame<Frame, IsPlanar>::type range;
00091     typedef typename range::const_type  const_range;
00092     
00093     typedef typename range::size_type        size_type;
00094     typedef typename range::value_type       value_type;
00095     typedef typename range::difference_type  difference_type;
00096     typedef typename range::reference        reference;
00097     
00098     typedef typename range::iterator               iterator;
00099     typedef typename const_range::iterator         const_iterator;
00100     typedef typename range::reverse_iterator       reverse_iterator;
00101     typedef typename const_range::reverse_iterator const_reverse_iterator;
00102         
00103     /* Create with size and optional initial value and
00104      * alignment */
00105     explicit buffer (size_type size = 0,
00106                      std::size_t alignment = 0,
00107             const Alloc alloc_in = Alloc())
00108         : _memory (0)
00109         , _align_in_bytes (alignment)
00110         , _alloc (alloc_in)
00111     {
00112         allocate_and_default_construct (size);
00113     }
00114     
00115     buffer (size_type size, 
00116             const Frame& frame_in,
00117             std::size_t alignment,
00118             const Alloc alloc_in = Alloc())
00119         : _memory (0)
00120         , _align_in_bytes (alignment)
00121         , _alloc (alloc_in)
00122     {
00123         allocate_and_fill (size, frame_in);
00124     }
00125     
00126     buffer (const buffer& buf)
00127         : _memory (0)
00128         , _align_in_bytes (buf._align_in_bytes)
00129         , _alloc (buf._alloc)
00130     {
00131         allocate_and_copy (buf.size (), buf._range);
00132     }
00133 
00134     template <typename F2, bool IP2, typename Alloc2>
00135     buffer (const buffer<F2, IP2, Alloc2>& buf)
00136         : _memory(0)
00137         , _align_in_bytes (buf._align_in_bytes)
00138         , _alloc (buf._alloc)
00139     {
00140        allocate_and_copy (buf.size (), buf._range);
00141     }
00142 
00143     buffer& operator= (const buffer& buf)
00144     {
00145         if (this->size () == buf.size ())
00146             copy_frames (buf, _range);
00147         else {
00148             buffer tmp (buf);
00149             swap (tmp);
00150         }
00151         return *this;
00152     }
00153 
00154     template <typename Buf>
00155     buffer& operator= (const Buf& buf)
00156     {
00157         if (this->size () == buf.size ())
00158             copy_frames (buf, _range);
00159         else {
00160             buffer tmp (buf);
00161             swap (tmp);
00162         }
00163         return *this;
00164     }
00165 
00166     ~buffer()
00167     {
00168         destruct_frames (_range);
00169         deallocate (_range.size ());
00170     }
00171 
00172     Alloc&       allocator () { return _alloc; }
00173     Alloc const& allocator () const { return _alloc; }
00174 
00175     size_type size () const
00176     {
00177         return _range.size ();
00178     }
00179     
00180     void swap (buffer& buf)
00181     {
00182         // required by MutableContainerConcept
00183         using std::swap;
00184         swap (_align_in_bytes, buf._align_in_bytes);
00185         swap (_memory,         buf._memory);
00186         swap (_range,          buf._range); 
00187         swap (_alloc,          buf._alloc);
00188     }    
00189 
00190     void recreate (size_type size,
00191                    std::size_t alignment=0,
00192                    const Alloc alloc_in = Alloc ())
00193     {
00194         if (size != _range.size () ||
00195             _align_in_bytes != alignment ||
00196             alloc_in != _alloc)
00197         {
00198             buffer tmp (size, alignment, alloc_in);
00199             swap (tmp);
00200         }
00201     }
00202     
00203     void recreate (size_type size_, 
00204                    const Frame& frame_in,
00205                    std::size_t alignment,
00206                    const Alloc alloc_in = Alloc())
00207     {
00208         if (size_ != size() ||
00209             _align_in_bytes != alignment ||
00210             alloc_in != _alloc)
00211         {
00212             buffer tmp (size_, frame_in, alignment, alloc_in);
00213             swap (tmp);
00214         }
00215     }
00216 
00217 #ifdef PSYNTH_BUFFER_MODEL_RANGE
00218     
00219     iterator frames () 
00220     { return _range.frames (); }
00221 
00222     const_iterator frames () const 
00223     { return _range.frames (); }
00224     
00225     iterator begin ()
00226     { return _range.begin (); }
00227     
00228     iterator end ()
00229     { return _range.end (); } // potential performance problem!
00230 
00231     const_iterator begin () const
00232     { return _range.begin (); }
00233     
00234     const_iterator end () const
00235     { return _range.end (); } // potential performance problem!
00236     
00237     reverse_iterator rbegin ()
00238     { return _range.rbegin (); }
00239     
00240     reverse_iterator rend ()
00241     { return _range.rend (); }
00242     
00243     const_reverse_iterator rbegin () const
00244     { return _range.rbegin (); }
00245     
00246     const_reverse_iterator rend () const
00247     { return _range.rend (); }
00248     
00249     reference operator [] (difference_type i)
00250     { return begin () [i]; } // potential performance problem!
00251 
00252     const reference operator [] (difference_type i) const
00253     { return begin () [i]; } // potential performance problem!
00254     
00255     iterator at (difference_type i)
00256     { return begin () + i; }
00257     
00258     const_iterator at (difference_type i) const
00259     { return begin () + i; }
00260 
00261 #endif /* PSYNTH_BUFFER_MODEL_RANGE */
00262     
00263 private:
00264     template <typename F, bool P, typename A> friend 
00265     const typename buffer<F, P, A>::range&
00266     range (buffer<F, P, A>& buf);
00267 
00268     template <typename F, bool P, typename A> friend 
00269     const typename buffer<F, P, A>::const_range
00270     const_range (const buffer<F, P, A>& buf);
00271     
00272     unsigned char* _memory;
00273     std::size_t    _align_in_bytes;
00274     allocator_type _alloc;
00275     range          _range;
00276     
00277     void allocate_and_default_construct (size_type size)
00278     { 
00279         try {
00280             allocate_ (size, boost::mpl::bool_<IsPlanar>());
00281             default_construct_frames (_range);
00282         } catch (...) {
00283             deallocate (size);
00284             throw;
00285         }
00286     }
00287 
00288     void allocate_and_fill (size_type size, const Frame& frame_in)
00289     {
00290         try {
00291             allocate_ (size, boost::mpl::bool_<IsPlanar>());
00292             uninitialized_fill_frames (_range, frame_in);
00293         } catch(...) {
00294             deallocate(size);
00295             throw;
00296         }
00297     }
00298 
00299     template <typename Range>
00300     void allocate_and_copy (size_type size, const Range& v)
00301     { 
00302         try {
00303             allocate_ (size, boost::mpl::bool_<IsPlanar>());
00304             uninitialized_copy_frames (v, _range);
00305         } catch(...) {
00306             deallocate(size);
00307             throw;
00308         }
00309     }
00310 
00311     void deallocate (size_type size)
00312     { 
00313         if (_memory)
00314             _alloc.deallocate (_memory, total_allocated_size_in_bytes (size));
00315     }
00316 
00317     std::size_t total_allocated_size_in_bytes (size_type size) const
00318     {
00319         std::size_t size_in_units = size * memunit_step (
00320             typename range::iterator ());
00321         if (IsPlanar)
00322             size_in_units = size_in_units * num_samples<range>::value;
00323         
00324         // return the size rounded up to the nearest byte
00325         return (size_in_units +
00326                 byte_to_memunit<typename range::iterator>::value - 1) /
00327             byte_to_memunit<typename range::iterator>::value
00328             + (_align_in_bytes > 0 ? _align_in_bytes - 1 : 0);
00329         // add extra padding in case we need to align the first buffer frame
00330     }
00331 
00332     std::size_t get_size_in_memunits (size_type size) const
00333     {
00334         // number of units per row
00335         size_type size_in_memunits =
00336             size * memunit_step (typename range::iterator ());
00337         if (_align_in_bytes > 0) {
00338             std::size_t alignment_in_memunits =
00339                 _align_in_bytes *
00340                 byte_to_memunit<typename range::iterator>::value;
00341             return align (size_in_memunits, alignment_in_memunits);
00342         }
00343         return size_in_memunits;
00344     }
00345     
00346     void allocate_ (const size_type& size, boost::mpl::false_)
00347     {
00348         // if it throws and _memory!=0 the client must deallocate _memory
00349         _memory = _alloc.allocate (total_allocated_size_in_bytes (size));
00350 
00351         unsigned char* tmp = (_align_in_bytes > 0) ?
00352             (unsigned char*) align ((std::size_t) _memory, _align_in_bytes) :
00353             _memory;
00354         
00355         _range = range (size, typename range::iterator (tmp));
00356     }
00357 
00358     void allocate_ (size_type size, boost::mpl::true_)
00359     {
00360         // if it throws and _memory!=0 the client must deallocate _memory
00361         std::size_t plane_size = get_size_in_memunits (size);
00362         _memory = _alloc.allocate (total_allocated_size_in_bytes (size));
00363         
00364         unsigned char* tmp = (_align_in_bytes > 0) ?
00365             (unsigned char*) align ((std::size_t)_memory, _align_in_bytes) :
00366             _memory;
00367         
00368         typename range::iterator first; 
00369         for (int i = 0; i < num_samples<range>::value; ++i)
00370         {
00371             dynamic_at_c (first, i) = (typename sample_type<range>::type *) tmp;
00372             memunit_advance (dynamic_at_c (first, i), plane_size * i);
00373         }
00374         
00375         _range = range (size, first);
00376     }
00377 };
00378 
00379 template <typename Frame, bool IsPlanar, typename Alloc>
00380 void swap (buffer<Frame, IsPlanar, Alloc>& buf1,
00381            buffer<Frame, IsPlanar, Alloc>& buf2)
00382 {
00383     buf1.swap (buf2); 
00384 }
00385 
00386 template <typename Frame1, bool IsPlanar1, typename Alloc1,
00387           typename Frame2, bool IsPlanar2, typename Alloc2>
00388 bool operator == (const buffer<Frame1, IsPlanar1, Alloc1>& buf1,
00389                   const buffer<Frame2, IsPlanar2, Alloc2>& buf2)
00390 {
00391     if ((void*)(&buf1) == (void*)(&buf2))
00392         return true;
00393     if (const_range (buf1).size() != const_range (buf2).size())
00394         return false;
00395     return equal_frames (const_range (buf1), const_range (buf2));
00396 }
00397 
00398 template <typename Frame1, bool IsPlanar1, typename Alloc1,
00399           typename Frame2, bool IsPlanar2, typename Alloc2>
00400 bool operator != (const buffer<Frame1, IsPlanar1, Alloc1>& buf1,
00401                   const buffer<Frame2, IsPlanar2, Alloc2>& buf2)
00402 {
00403     return !(buf1 == buf2);
00404 }
00405 
00414 template <typename Frame, bool IsPlanar, typename Alloc> inline 
00415 const typename buffer<Frame, IsPlanar, Alloc>::range&
00416 range (buffer<Frame, IsPlanar, Alloc>& buf)
00417 {
00418     return buf._range;
00419 }
00420 
00424 template <typename Frame, bool IsPlanar, typename Alloc> inline 
00425 const typename buffer <Frame, IsPlanar, Alloc>::const_range
00426 const_range (const buffer<Frame,IsPlanar,Alloc>& buf)
00427 { 
00428     return typename buffer<Frame, IsPlanar, Alloc>::const_range (buf._range); 
00429 }
00432 /*
00433  *
00434  *  FrameBasedConcept
00435  *
00436  */
00437 
00438 template <typename Frame, bool IsPlanar, typename Alloc>
00439 struct sample_type<buffer<Frame,IsPlanar,Alloc> > :
00440     public sample_type<Frame> {}; 
00441 
00442 template <typename Frame, bool IsPlanar, typename Alloc>
00443 struct channel_space_type<buffer<Frame,IsPlanar,Alloc> >  :
00444     public channel_space_type<Frame> {};
00445 
00446 template <typename Frame, bool IsPlanar, typename Alloc>
00447 struct sample_mapping_type<buffer<Frame,IsPlanar,Alloc> > :
00448     public sample_mapping_type<Frame> {};
00449 
00450 template <typename Frame, bool IsPlanar, typename Alloc>
00451 struct is_planar<buffer<Frame,IsPlanar,Alloc> > :
00452     public boost::mpl::bool_<IsPlanar> {};
00453 
00454 //#ifdef _MSC_VER
00455 //#pragma warning(pop)
00456 //#endif
00457 
00458 } /* namespace sound */
00459 } /* namespace psynth */
00460 
00461 #endif /* PSYNTH_SOUND_BUFFER */