libpsynth 0.2.1
/home/raskolnikov/dev/psynth/trunk/src/psynth/sound/bit_aligned_frame_reference.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_BIT_ALIGNED_PIXEL_REFERENCE_HPP
00040 #define PSYNTH_SOUND_BIT_ALIGNED_PIXEL_REFERENCE_HPP
00041 
00042 #include <functional>
00043 #include <boost/mpl/accumulate.hpp>
00044 #include <boost/mpl/at.hpp>
00045 #include <boost/mpl/bool.hpp>
00046 #include <boost/mpl/if.hpp>
00047 #include <boost/mpl/plus.hpp>
00048 #include <boost/mpl/push_back.hpp>
00049 #include <boost/mpl/vector.hpp>
00050 
00051 #include <psynth/base/compat.hpp>
00052 #include <psynth/sound/frame.hpp>
00053 #include <psynth/sound/sample.hpp>
00054 
00055 namespace psynth
00056 {
00057 namespace sound
00058 {
00059 
00069 template <int RangeSize, bool Mutable>
00070 class bit_range
00071 {
00072 public:
00073     typedef typename boost::mpl::if_c<Mutable,
00074                                unsigned char,
00075                                const unsigned char>::type byte_type;
00076     
00077     typedef std::ptrdiff_t difference_type;
00078     template <int RS, bool M> friend class bit_range;
00079 
00080 private:
00081     byte_type* _current_byte;   // the starting byte of the bit range
00082     int        _bit_offset;     // offset from the beginning of the
00083                                 // current byte. 0<=_bit_offset<=7
00084 
00085 public:
00086     bit_range ()
00087         : _current_byte (0)
00088         , _bit_offset (0)
00089     {}
00090     
00091     bit_range (byte_type* current_byte, int bit_offset)
00092         : _current_byte (current_byte)
00093         , _bit_offset(bit_offset)
00094     { assert (bit_offset >= 0 && bit_offset < 8); } 
00095 
00096     bit_range (const bit_range& br)
00097         : _current_byte (br._current_byte)
00098         , _bit_offset (br._bit_offset)
00099     {}
00100     
00101     template <bool M>
00102     bit_range (const bit_range<RangeSize, M>& br)
00103         : _current_byte(br._current_byte)
00104         , _bit_offset (br._bit_offset)
00105     {}
00106 
00107     bit_range& operator= (const bit_range& br)
00108     {
00109         _current_byte = br._current_byte;
00110         _bit_offset   = br._bit_offset;
00111         return *this;
00112     }
00113     
00114     bool operator== (const bit_range& br) const
00115     {
00116         return
00117             _current_byte == br._current_byte &&
00118             _bit_offset == br._bit_offset;
00119     }
00120 
00121     bit_range& operator++ ()
00122     {
00123         _current_byte += (_bit_offset + RangeSize) / 8;
00124         _bit_offset    = (_bit_offset + RangeSize) % 8;
00125         return *this;
00126     }
00127     
00128     bit_range& operator-- ()
00129     {
00130         bit_advance (- RangeSize);
00131         return *this;
00132     }
00133 
00134     void bit_advance (difference_type num_bits)
00135     {
00136         int new_offset = int (_bit_offset + num_bits);
00137         _current_byte += new_offset / 8;
00138         _bit_offset    = new_offset % 8;
00139         if (_bit_offset<0) {
00140             _bit_offset+=8;
00141             --_current_byte;
00142         }
00143     }
00144     
00145     difference_type bit_distance_to (const bit_range& b) const
00146     {
00147         return
00148             (b.current_byte() - current_byte()) * 8 +
00149             b.bit_offset() - bit_offset();
00150     }
00151     
00152     byte_type* current_byte () const
00153     {
00154         return _current_byte;
00155     }
00156 
00157     int bit_offset () const
00158     {
00159         return _bit_offset;
00160     }
00161 };
00162 
00209 template <typename BitField,
00210           typename SampleBitSizes,
00211           // MPL integral vector defining the number of bits for each
00212           // sample. For example, for 565RGB, vector_c<int, 5, 6, 5>
00213           typename Layout, 
00214           bool IsMutable>
00215 struct bit_aligned_frame_reference
00216 {
00217     BOOST_STATIC_CONSTANT(
00218         int, bit_size = (boost::mpl::accumulate<SampleBitSizes, boost::mpl::int_<0>,
00219                                          boost::mpl::plus<boost::mpl::_1, boost::mpl::_2>
00220                                          >::type::value));
00221     
00222     typedef psynth::sound::bit_range<bit_size, IsMutable> bit_range_type;
00223     typedef BitField  bitfield_type;
00224     typedef typename boost::mpl::if_c<IsMutable,
00225                                unsigned char*,
00226                                const unsigned char*>::type data_ptr_type;
00227     typedef Layout layout;
00228 
00229     typedef typename packed_frame_type<
00230         bitfield_type, SampleBitSizes,Layout>::type value_type;
00231     typedef const bit_aligned_frame_reference reference;
00232     typedef const bit_aligned_frame_reference<
00233         BitField, SampleBitSizes, Layout, false> const_reference;
00234 
00235     BOOST_STATIC_CONSTANT(bool, is_mutable = IsMutable);
00236 
00237     bit_aligned_frame_reference () {}
00238     
00239     bit_aligned_frame_reference (data_ptr_type data_ptr, int bit_offset)
00240         : _bit_range (data_ptr, bit_offset)
00241     {}
00242 
00243     explicit bit_aligned_frame_reference (const bit_range_type& bit_range)
00244         : _bit_range (bit_range)
00245     {}
00246     
00247     template <bool IsMutable2> bit_aligned_frame_reference (
00248         const bit_aligned_frame_reference<
00249             BitField, SampleBitSizes, Layout, IsMutable2>& p)
00250         : _bit_range(p._bit_range)
00251     {}
00252 
00253     // Mono references can be constructed from the sample reference
00254     explicit bit_aligned_frame_reference (
00255         const typename kth_element_type<
00256             bit_aligned_frame_reference, 0>::type sample0)
00257         : _bit_range (static_cast<data_ptr_type>(&sample0), sample0.first_bit())
00258     {
00259         BOOST_STATIC_ASSERT((num_samples<
00260                                  bit_aligned_frame_reference>::value == 1));
00261     }
00262 
00263     // Construct from another compatible frame type
00264     bit_aligned_frame_reference (const bit_aligned_frame_reference& p)
00265         : _bit_range(p._bit_range)
00266     {}
00267     
00268     template <typename BF, typename CR>
00269     bit_aligned_frame_reference (packed_frame<BF,CR,Layout>& p)
00270         : _bit_range (static_cast<data_ptr_type>(&sound::at_c<0>( p)),
00271                       sound::at_c<0> (p).first_bit ())
00272     {
00273         check_compatible<packed_frame<BF,CR,Layout> >();
00274     }
00275 
00276     const bit_aligned_frame_reference& operator= (
00277         const bit_aligned_frame_reference& p) const
00278     {
00279         static_copy (p,*this);
00280         return *this;
00281     }
00282     
00283     template <typename P>
00284     const bit_aligned_frame_reference& operator= (const P& p) const
00285     {
00286         assign (p, boost::mpl::bool_<is_frame<P>::value>());
00287         return *this;
00288     } 
00289 
00290     template <typename P>
00291     bool operator== (const P& p) const
00292     {
00293         return equal (p, boost::mpl::bool_<is_frame<P>::value>());
00294     }
00295     
00296     template <typename P>
00297     bool operator!= (const P& p) const
00298     { return !(*this == p); }
00299 
00300     const bit_aligned_frame_reference* operator->() const
00301     { return this; }
00302 
00303     const bit_range_type& bit_range() const
00304     { return _bit_range; }
00305 
00306 private:
00307     mutable bit_range_type _bit_range;
00308 
00309     template <typename B, typename C, typename L, bool M>
00310     friend struct bit_aligned_frame_reference;
00311 
00312     template <typename Frame>
00313     static void check_compatible()
00314     {
00315         base::psynth_function_requires<FramesCompatibleConcept<
00316             Frame, bit_aligned_frame_reference> >();
00317     }
00318 
00319     template <typename Frame>
00320     void assign (const Frame& p, boost::mpl::true_) const
00321     {
00322         check_compatible<Frame>();
00323         static_copy (p, *this);
00324     }
00325     
00326     template <typename Frame>
00327     bool equal (const Frame& p, boost::mpl::true_) const
00328     {
00329         check_compatible<Frame>();
00330         return static_equal (*this, p);
00331     } 
00332 
00333     static void check_mono ()
00334     {
00335         BOOST_STATIC_ASSERT((boost::is_same<
00336                              typename Layout::channel_space_type,
00337                              mono_space>::value));
00338     }
00339     
00340     template <typename Sample>
00341     void assign (const Sample& chan, boost::mpl::false_) const
00342     {
00343         check_mono ();
00344         sound::at_c<0>(*this) = chan;
00345     }
00346     
00347     template <typename Sample>
00348     bool equal (const Sample& chan, boost::mpl::false_) const
00349     {
00350         check_mono ();
00351         return sound::at_c<0>(*this)==chan;
00352     }
00353 };
00354 
00355 /*
00356  *
00357  *    ChannelBasedConcept
00358  *
00359  */
00360 
00361 template <typename BitField, typename SampleBitSizes,
00362           typename L, bool IsMutable, int K>  
00363 struct kth_element_type<bit_aligned_frame_reference<
00364                             BitField,SampleBitSizes,L,IsMutable>, K>
00365 {
00366 public:
00367     typedef const packed_dynamic_sample_reference<
00368     BitField, boost::mpl::at_c<SampleBitSizes, K>::type::value, IsMutable> type;
00369 };
00370 
00371 template <typename B, typename C, typename L, bool M, int K>  
00372 struct kth_element_reference_type<bit_aligned_frame_reference<B,C,L,M>, K>
00373     : public kth_element_type<bit_aligned_frame_reference<B,C,L,M>, K> {};
00374 
00375 template <typename B, typename C, typename L, bool M, int K>  
00376 struct kth_element_const_reference_type<bit_aligned_frame_reference<B,C,L,M>, K>
00377     : public kth_element_type<bit_aligned_frame_reference<B,C,L,M>, K> {};
00378 
00379 
00380 namespace detail
00381 {
00382 
00383 // returns sum of IntegralVector[0] ... IntegralVector[K-1]
00384 template <typename IntegralVector, int K> 
00385 struct sum_k :
00386         public boost::mpl::plus<sum_k<IntegralVector, K-1>,
00387                          typename boost::mpl::at_c<IntegralVector, K-1>::type > {};
00388 
00389 template <typename IntegralVector>
00390 struct sum_k<IntegralVector, 0> : public boost::mpl::int_<0> {};
00391 
00392 } /* namespace detail */
00393 
00395 template <int K, typename BitField, typename SampleBitSizes,
00396           typename L, bool Mutable> inline
00397 typename kth_element_reference_type<
00398     bit_aligned_frame_reference<BitField,SampleBitSizes,L,Mutable>,K>::type
00399 at_c (const bit_aligned_frame_reference<BitField,SampleBitSizes,L,Mutable>& p)
00400 { 
00401     typedef bit_aligned_frame_reference<BitField,SampleBitSizes,L,Mutable> frame_t;
00402     typedef typename kth_element_reference_type<frame_t,K>::type sample_t;
00403     typedef typename frame_t::bit_range_type bit_range_type;
00404 
00405     bit_range_type bit_range (p.bit_range());
00406     bit_range.bit_advance (detail::sum_k<SampleBitSizes, K>::value);
00407 
00408     return sample_t (bit_range.current_byte(), bit_range.bit_offset ()); 
00409 }
00410 
00411 /*
00412  *
00413  *    FrameConcept
00414  *
00415  */
00416 
00421 template <typename B, typename C, typename L, bool M>  
00422 struct is_frame<bit_aligned_frame_reference<B,C,L,M> > : public boost::mpl::true_{};
00423 
00424 /*
00425  *
00426  *    FrameBasedConcept
00427  *
00428  */
00429 
00430 template <typename B, typename C, typename L, bool M>
00431 struct channel_space_type<bit_aligned_frame_reference<B,C,L,M> >
00432 {
00433     typedef typename L::channel_space type;
00434 }; 
00435 
00436 template <typename B, typename C, typename L, bool M>
00437 struct sample_mapping_type<bit_aligned_frame_reference<B,C,L,M> >
00438 {
00439     typedef typename L::sample_mapping type;
00440 }; 
00441 
00442 template <typename B, typename C, typename L, bool M>
00443 struct is_planar<bit_aligned_frame_reference<B,C,L,M> > : boost::mpl::false_ {}; 
00444 
00445 
00446 /*
00447  *
00448  *    frame_reference_type
00449  *
00450  */
00451 
00452 namespace detail
00453 {
00454 
00455 // returns a vector containing K copies of the type T
00456 template <unsigned K, typename T>
00457 struct k_copies;
00458 
00459 template <typename T> struct k_copies<0,T>
00460 {
00461     typedef boost::mpl::vector0<> type;
00462 };
00463 
00464 template <unsigned K, typename T>
00465 struct k_copies : public boost::mpl::push_back<typename k_copies<K-1,T>::type, T> {};
00466 
00467 } /* namespace detail */
00468 
00469 /*
00470   Constructs a homogeneous bit_aligned_frame_reference given a sample
00471   reference
00472 */
00473 template <typename BitField, int NumBits, typename Layout> 
00474 struct frame_reference_type<const packed_dynamic_sample_reference<
00475                                 BitField,NumBits,false>, Layout, false, false>
00476 {
00477 private:
00478     typedef typename boost::mpl::size<typename Layout::channel_space>::type
00479     size_type;
00480 
00481     typedef typename detail::k_copies<
00482         size_type::value, boost::mpl::integral_c<unsigned,NumBits> >::type
00483     sample_bit_sizes_type;
00484 
00485 public:
00486     typedef bit_aligned_frame_reference<BitField, sample_bit_sizes_type,
00487                                         Layout, false> type;
00488 };
00489 
00490 
00491 /*
00492   Same but for the mutable case. We cannot combine the mutable and
00493   read-only cases because this triggers ambiguity
00494 */
00495 template <typename BitField, int NumBits, typename Layout> 
00496 struct frame_reference_type<const packed_dynamic_sample_reference<
00497                                 BitField,NumBits,true>, Layout, false, true>
00498 {
00499 private:
00500     typedef typename boost::mpl::size<typename Layout::channel_space>::type
00501     size_type;
00502 
00503     typedef typename detail::k_copies<
00504         size_type::value, boost::mpl::integral_c<unsigned, NumBits> >::type
00505     sample_bit_sizes_type;
00506     
00507 public:
00508     typedef bit_aligned_frame_reference<
00509     BitField, sample_bit_sizes_type, Layout, true> type;
00510 };
00511 
00512 } /* namespace sound */
00513 } /* namespace psynth */
00514 
00515 namespace std
00516 {
00517 
00518 /*
00519   We are forced to define swap inside std namespace because on some
00520   platforms (Visual Studio 8) STL calls swap qualified.
00521   
00522   swap with 'left bias': 
00523   - swap between proxy and anything
00524   - swap between value type and proxy
00525   - swap between proxy and proxy
00526 
00527   Having three overloads allows us to swap between different (but
00528   compatible) models of FrameConcept
00529 */
00530 template <typename B, typename C, typename L, typename R> inline
00531 void swap (const psynth::sound::bit_aligned_frame_reference<B,C,L,true> x, R& y)
00532 { 
00533     psynth::sound::swap_proxy<
00534         typename psynth::sound::bit_aligned_frame_reference<
00535             B,C,L,true>::value_type>(x, y); 
00536 }
00537 
00538 
00539 template <typename B, typename C, typename L> inline
00540 void swap (typename psynth::sound::bit_aligned_frame_reference<
00541                B,C,L,true>::value_type& x,
00542            const psynth::sound::bit_aligned_frame_reference<B,C,L,true> y)
00543 { 
00544     psynth::sound::swap_proxy<
00545         typename psynth::sound::bit_aligned_frame_reference<
00546             B,C,L,true>::value_type>(x, y); 
00547 }
00548 
00549 template <typename B, typename C, typename L> inline
00550 void swap (const psynth::sound::bit_aligned_frame_reference<B,C,L,true> x,
00551            const psynth::sound::bit_aligned_frame_reference<B,C,L,true> y)
00552 { 
00553     psynth::sound::swap_proxy<
00554         typename psynth::sound::bit_aligned_frame_reference<
00555             B,C,L,true>::value_type> (x, y); 
00556 }
00557 
00558 } /* namespace std */
00559 
00560 #endif /* PSYNTH_SOUND_BIT_ALIGNED_FRAME_REFERENCE */