@@ -102,6 +102,11 @@ extern "C"{
102102}
103103#endif
104104
105+ template <typename T>
106+ inline int32_t truncate (void *data, size_t i, int32_t bitmask, int32_t bitshift) {
107+ return ((int32_t (((T *)data)[i]) & bitmask) << bitshift) >> bitshift;
108+ }
109+
105110template <class A > void G3Timestream::save (A &ar, unsigned v) const
106111{
107112 ar & cereal::make_nvp (" G3FrameObject" ,
@@ -122,30 +127,52 @@ template <class A> void G3Timestream::save(A &ar, unsigned v) const
122127 if (units != Counts && units != None)
123128 log_fatal (" Cannot use FLAC on non-counts timestreams" );
124129
130+ DataType data_type_out = TS_FLOAT;
131+ int32_t bitmask, bitshift;
132+ switch (flac_depth_) {
133+ case 24 :
134+ bitmask = 0x00ffffff ;
135+ bitshift = 8 ;
136+ break ;
137+ case 32 :
138+ bitmask = 0xffffffff ;
139+ bitshift = 0 ;
140+ if (data_type_ == TS_INT64 || data_type_ == TS_INT32)
141+ data_type_out = TS_INT32;
142+ break ;
143+ default :
144+ log_fatal (" Invalid FLAC bit depth %d" , (int ) flac_depth_);
145+ }
146+
147+ ar & cereal::make_nvp (" flac_depth" , flac_depth_);
148+ ar & cereal::make_nvp (" data_type" , data_type_out);
149+
125150 // Copy to 24-bit integers
126151 inbuf.resize (size ());
127152 switch (data_type_) {
128153 case TS_DOUBLE:
129154 for (size_t i = 0 ; i < size (); i++)
130- inbuf[i] = (( int32_t ((( double *) data_)[i]) & 0x00ffffff ) << 8 ) >> 8 ;
155+ inbuf[i] = truncate< double >( data_, i, bitmask, bitshift) ;
131156 break ;
132157 case TS_FLOAT:
133158 for (size_t i = 0 ; i < size (); i++)
134- inbuf[i] = (( int32_t ((( float *) data_)[i]) & 0x00ffffff ) << 8 ) >> 8 ;
159+ inbuf[i] = truncate< float >( data_, i, bitmask, bitshift) ;
135160 break ;
136161 case TS_INT32:
137- {
162+ if (flac_depth_ == 24 ) {
138163 // Using this rather raw form for the loop can enable automatic
139164 // unrolling and vectorization.
140165 int32_t * in_ptr=(int32_t *)data_;
141166 int32_t * out_ptr=&inbuf[0 ];
142167 for (int32_t * end=in_ptr+size (); in_ptr!=end; in_ptr++,out_ptr++)
143168 *out_ptr = ((*in_ptr & 0x00ffffff ) << 8 ) >> 8 ;
169+ } else {
170+ memcpy (inbuf.data (), data_, size () * sizeof (int32_t ));
144171 }
145172 break ;
146173 case TS_INT64:
147174 for (size_t i = 0 ; i < size (); i++)
148- inbuf[i] = (( int32_t ((( int64_t *) data_)[i]) & 0x00ffffff ) << 8 ) >> 8 ;
175+ inbuf[i] = truncate< int64_t >( data_, i, bitmask, bitshift) ;
149176 break ;
150177 default :
151178 log_fatal (" Unknown timestream datatype %d" , data_type_);
@@ -182,7 +209,7 @@ template <class A> void G3Timestream::save(A &ar, unsigned v) const
182209 FLAC__StreamEncoder *encoder = FLAC__stream_encoder_new ();
183210 FLAC__stream_encoder_set_channels (encoder, 1 );
184211 // XXX: should assert if high-order 8 bits are not clear
185- FLAC__stream_encoder_set_bits_per_sample (encoder, 24 );
212+ FLAC__stream_encoder_set_bits_per_sample (encoder, flac_depth_ );
186213 FLAC__stream_encoder_set_compression_level (encoder, use_flac_);
187214 FLAC__stream_encoder_set_do_md5 (encoder, false );
188215 FLAC__stream_encoder_init_stream (encoder,
@@ -262,6 +289,13 @@ template <class A> void G3Timestream::load(A &ar, unsigned v)
262289 if (units != Counts && units != None)
263290 log_fatal (" Cannot use FLAC on non-counts timestreams" );
264291
292+ if (v >= 4 ) {
293+ ar & cereal::make_nvp (" flac_depth" , flac_depth_);
294+ ar & cereal::make_nvp (" data_type" , data_type_);
295+ } else {
296+ data_type_ = TS_FLOAT;
297+ }
298+
265299 ar & cereal::make_nvp (" nanflag" , nanflag);
266300 if (nanflag == SomeNan)
267301 ar & cereal::make_nvp (" nanmask" , nanbuf);
@@ -281,14 +315,22 @@ template <class A> void G3Timestream::load(A &ar, unsigned v)
281315 FLAC__stream_decoder_finish (decoder);
282316 FLAC__stream_decoder_delete (decoder);
283317
318+ // Short-circuit for full-depth INT32.
319+ if (data_type_ == TS_INT32 && flac_depth_ == 32 ) {
320+ root_data_ref_ = std::shared_ptr<std::vector<int32_t > >(
321+ callback.outbuf );
322+ len_ = callback.outbuf ->size ();
323+ data_ = &(*callback.outbuf )[0 ];
324+ return ;
325+ }
326+
284327 // Represent data as floats internally. These have the same
285328 // significand depth (24 bits) as the max. bit depth of the
286329 // reference FLAC encoder we use, so no data are lost, and
287330 // allow NaNs, unlike int32_ts, which we try to pull through
288331 // the process to signal missing data.
289332 float *data = new float [callback.outbuf ->size ()];
290333 root_data_ref_ = std::shared_ptr<float []>(data);
291- data_type_ = TS_FLOAT;
292334 len_ = callback.outbuf ->size ();
293335 data_ = data;
294336
@@ -361,7 +403,7 @@ template <class A> void G3Timestream::load(A &ar, unsigned v)
361403
362404G3Timestream::G3Timestream (const G3Timestream &r) :
363405 units (r.units ), start (r.start ), stop (r.stop ), use_flac_ (r.use_flac_ ),
364- len_ (r.len_ ), data_type_ (r.data_type_ )
406+ flac_depth_ (r. flac_depth_ ), len_ (r.len_ ), data_type_ (r.data_type_ )
365407{
366408 // Copy constructor needs to copy data, which always involves
367409 // allocating the internal buffer.
@@ -431,6 +473,14 @@ void G3Timestream::SetFLACCompression(int use_flac)
431473#endif
432474}
433475
476+ void G3Timestream::SetFLACDepth (int bit_depth)
477+ {
478+ if (bit_depth != 24 && bit_depth != 32 )
479+ log_fatal (" Invalid flac bit depth %d" , bit_depth);
480+
481+ flac_depth_ = bit_depth;
482+ }
483+
434484G3Timestream G3Timestream::operator +(const G3Timestream &r) const
435485{
436486 G3Timestream ret (*this );
@@ -764,12 +814,32 @@ uint8_t G3TimestreamMap::GetCompressionLevel() const
764814 return begin ()->second ->use_flac_ ;
765815}
766816
817+ uint8_t G3TimestreamMap::GetBitDepth () const
818+ {
819+ if (begin () == end ())
820+ return 0 ;
821+
822+ return begin ()->second ->flac_depth_ ;
823+ }
824+
767825void G3TimestreamMap::SetFLACCompression (int compression_level)
768826{
827+ // Check for errors
828+ begin ()->second ->SetFLACCompression (compression_level);
829+
769830 for (auto & ts : *this )
770831 ts.second ->use_flac_ = compression_level;
771832}
772833
834+ void G3TimestreamMap::SetFLACDepth (int bit_depth)
835+ {
836+ // Check for errors
837+ begin ()->second ->SetFLACDepth (bit_depth);
838+
839+ for (auto & ts : *this )
840+ ts.second ->flac_depth_ = bit_depth;
841+ }
842+
773843void G3TimestreamMap::Compactify ()
774844{
775845 // Check if already compacted
@@ -1069,7 +1139,8 @@ struct PyBufferOwner {
10691139static G3TimestreamMapPtr
10701140G3TimestreamMap_from_numpy (std::vector<std::string> keys,
10711141 boost::python::object data, G3Time start, G3Time stop,
1072- G3Timestream::TimestreamUnits units, int compression_level, bool copy_data)
1142+ G3Timestream::TimestreamUnits units, int compression_level,
1143+ bool copy_data, int bit_depth)
10731144{
10741145 G3TimestreamMapPtr x (new G3TimestreamMap);
10751146
@@ -1116,6 +1187,7 @@ G3TimestreamMap_from_numpy(std::vector<std::string> keys,
11161187 templ.start = start;
11171188 templ.stop = stop;
11181189 templ.SetFLACCompression (compression_level);
1190+ templ.SetFLACDepth (bit_depth);
11191191 if (strcmp (v->v .format , " d" ) == 0 ) {
11201192 templ.data_type_ = G3Timestream::TS_DOUBLE;
11211193 } else if (strcmp (v->v .format , " f" ) == 0 ) {
@@ -1347,6 +1419,10 @@ PYBINDINGS("core") {
13471419 " Pass True to turn on FLAC compression when serialized. "
13481420 " FLAC compression only works if the timestream is in units of "
13491421 " counts." )
1422+ .def (" SetFLACDepth" , &G3Timestream::SetFLACDepth,
1423+ " Change the bit depth for FLAC compression. "
1424+ " FLAC compression only works if the timestream is in units of "
1425+ " counts." )
13501426 .def_readwrite (" units" , &G3Timestream::units,
13511427 " Units of the data in the timestream, stored as one of the "
13521428 " members of core.G3TimestreamUnits." )
@@ -1361,6 +1437,8 @@ PYBINDINGS("core") {
13611437 .add_property (" compression_level" , &G3Timestream::GetCompressionLevel,
13621438 &G3Timestream::SetFLACCompression, " Level of FLAC compression used for this timestream. "
13631439 " This can only be non-zero if the timestream is in units of counts." )
1440+ .add_property (" bit_depth" , &G3Timestream::GetBitDepth,
1441+ &G3Timestream::SetFLACDepth, " Bit depth of FLAC compression used for this timestream." )
13641442 .def (" _assert_congruence" , &G3Timestream::G3TimestreamPythonHelpers::G3Timestream_assert_congruence,
13651443 " log_fatal() if units, length, start, or stop times do not match" )
13661444 .def (" _cxxslice" , &G3Timestream::G3TimestreamPythonHelpers::G3Timestream_getslice, " Slice-only __getitem__" )
@@ -1382,7 +1460,7 @@ PYBINDINGS("core") {
13821460 bp::default_call_policies (),
13831461 (bp::arg (" keys" ), bp::arg (" data" ), bp::arg (" start" )=G3Time (0 ),
13841462 bp::arg (" stop" )=G3Time (0 ), bp::arg (" units" ) = G3Timestream::TimestreamUnits::None,
1385- bp::arg (" compression_level" ) = 0 , bp::arg (" copy_data" ) = true )),
1463+ bp::arg (" compression_level" ) = 0 , bp::arg (" copy_data" ) = true , bp::arg ( " bit_depth " ) = 24 )),
13861464 " Create a timestream map from a numpy array or other numeric python iterable. "
13871465 " Each row of the 2D input array will correspond to a single timestream, with "
13881466 " the key set to the correspondingly-indexed entry of <keys>. If <copy_data> "
@@ -1398,6 +1476,10 @@ PYBINDINGS("core") {
13981476 " Pass True to turn on FLAC compression when serialized. "
13991477 " FLAC compression only works if the timestreams are in units of "
14001478 " counts." )
1479+ .def (" SetFLACDepth" , &G3TimestreamMap::SetFLACDepth,
1480+ " Change the bit depth for FLAC compression. "
1481+ " FLAC compression only works if the timestreams are in units of "
1482+ " counts." )
14011483 .add_property (" start" , &G3TimestreamMap::GetStartTime,
14021484 &G3TimestreamMap::SetStartTime,
14031485 " Time of the first sample in the time stream" )
@@ -1417,6 +1499,9 @@ PYBINDINGS("core") {
14171499 &G3TimestreamMap::SetFLACCompression,
14181500 " Level of FLAC compression used for this timestream map. "
14191501 " This can only be non-zero if the timestream is in units of counts." )
1502+ .add_property (" bit_depth" , &G3TimestreamMap::GetBitDepth,
1503+ &G3TimestreamMap::SetFLACDepth,
1504+ " Bit depth of FLAC compression used for this timestream map." )
14201505 ;
14211506 register_pointer_conversions<G3TimestreamMap>();
14221507
0 commit comments