|
libpsynth 0.2.1
|
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 */
1.7.4