Merged with trunk revision 600
[ardour.git] / libs / libsndfile / src / double64.c
1 /*
2 ** Copyright (C) 1999-2005 Erik de Castro Lopo <erikd@mega-nerd.com>
3 **
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
8 **
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 ** GNU Lesser General Public License for more details.
13 **
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include        "sfconfig.h"
20
21 #include        <stdio.h>
22 #include        <stdlib.h>
23 #include        <string.h>
24
25 #include        "sndfile.h"
26 #include        "sfendian.h"
27 #include        "common.h"
28 #include        "float_cast.h"
29
30 #if CPU_IS_LITTLE_ENDIAN
31         #define DOUBLE64_READ   double64_le_read
32         #define DOUBLE64_WRITE  double64_le_write
33 #elif CPU_IS_BIG_ENDIAN
34         #define DOUBLE64_READ   double64_be_read
35         #define DOUBLE64_WRITE  double64_be_write
36 #endif
37
38 /* A 32 number which will not overflow when multiplied by sizeof (double). */
39 #define SENSIBLE_LEN    (0x8000000)
40
41 /*--------------------------------------------------------------------------------------------
42 **      Processor floating point capabilities. double64_get_capability () returns one of the
43 **      latter three values.
44 */
45
46 enum
47 {       DOUBLE_UNKNOWN          = 0x00,
48         DOUBLE_CAN_RW_LE        = 0x23,
49         DOUBLE_CAN_RW_BE        = 0x34,
50         DOUBLE_BROKEN_LE        = 0x45,
51         DOUBLE_BROKEN_BE        = 0x56
52 } ;
53
54 /*--------------------------------------------------------------------------------------------
55 **      Prototypes for private functions.
56 */
57
58 static sf_count_t               host_read_d2s   (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
59 static sf_count_t               host_read_d2i   (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
60 static sf_count_t               host_read_d2f   (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
61 static sf_count_t               host_read_d             (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
62
63 static sf_count_t               host_write_s2d  (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
64 static sf_count_t               host_write_i2d  (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
65 static sf_count_t               host_write_f2d  (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
66 static sf_count_t               host_write_d    (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
67
68 static void             double64_peak_update    (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) ;
69
70 static int              double64_get_capability (SF_PRIVATE *psf) ;
71
72 static sf_count_t       replace_read_d2s        (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;
73 static sf_count_t       replace_read_d2i        (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;
74 static sf_count_t       replace_read_d2f        (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;
75 static sf_count_t       replace_read_d  (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;
76
77 static sf_count_t       replace_write_s2d       (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ;
78 static sf_count_t       replace_write_i2d       (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ;
79 static sf_count_t       replace_write_f2d       (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ;
80 static sf_count_t       replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ;
81
82 static  void    d2bd_read (double *buffer, int count) ;
83 static  void    bd2d_write (double *buffer, int count) ;
84
85 /*--------------------------------------------------------------------------------------------
86 **      Exported functions.
87 */
88
89 int
90 double64_init   (SF_PRIVATE *psf)
91 {       static int double64_caps ;
92
93         double64_caps = double64_get_capability (psf) ;
94
95         psf->blockwidth = sizeof (double) * psf->sf.channels ;
96
97         if (psf->mode == SFM_READ || psf->mode == SFM_RDWR)
98         {       switch (psf->endian + double64_caps)
99                 {       case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
100                                         psf->float_endswap = SF_FALSE ;
101                                         psf->read_short         = host_read_d2s ;
102                                         psf->read_int           = host_read_d2i ;
103                                         psf->read_float         = host_read_d2f ;
104                                         psf->read_double        = host_read_d ;
105                                         break ;
106
107                         case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
108                                         psf->float_endswap = SF_FALSE ;
109                                         psf->read_short         = host_read_d2s ;
110                                         psf->read_int           = host_read_d2i ;
111                                         psf->read_float         = host_read_d2f ;
112                                         psf->read_double        = host_read_d ;
113                                         break ;
114
115                         case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
116                                         psf->float_endswap = SF_TRUE ;
117                                         psf->read_short         = host_read_d2s ;
118                                         psf->read_int           = host_read_d2i ;
119                                         psf->read_float         = host_read_d2f ;
120                                         psf->read_double        = host_read_d ;
121                                         break ;
122
123                         case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
124                                         psf->float_endswap = SF_TRUE ;
125                                         psf->read_short         = host_read_d2s ;
126                                         psf->read_int           = host_read_d2i ;
127                                         psf->read_float         = host_read_d2f ;
128                                         psf->read_double        = host_read_d ;
129                                         break ;
130
131                         /* When the CPU is not IEEE compatible. */
132                         case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
133                                         psf->float_endswap = SF_FALSE ;
134                                         psf->read_short         = replace_read_d2s ;
135                                         psf->read_int           = replace_read_d2i ;
136                                         psf->read_float         = replace_read_d2f ;
137                                         psf->read_double        = replace_read_d ;
138                                         break ;
139
140                         case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
141                                         psf->float_endswap = SF_FALSE ;
142                                         psf->read_short         = replace_read_d2s ;
143                                         psf->read_int           = replace_read_d2i ;
144                                         psf->read_float         = replace_read_d2f ;
145                                         psf->read_double        = replace_read_d ;
146                                         break ;
147
148                         case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
149                                         psf->float_endswap = SF_TRUE ;
150                                         psf->read_short         = replace_read_d2s ;
151                                         psf->read_int           = replace_read_d2i ;
152                                         psf->read_float         = replace_read_d2f ;
153                                         psf->read_double        = replace_read_d ;
154                                         break ;
155
156                         case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
157                                         psf->float_endswap = SF_TRUE ;
158                                         psf->read_short         = replace_read_d2s ;
159                                         psf->read_int           = replace_read_d2i ;
160                                         psf->read_float         = replace_read_d2f ;
161                                         psf->read_double        = replace_read_d ;
162                                         break ;
163
164                         default : break ;
165                         } ;
166                 } ;
167
168         if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR)
169         {       switch (psf->endian + double64_caps)
170                 {       case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) :
171                                         psf->float_endswap = SF_FALSE ;
172                                         psf->write_short        = host_write_s2d ;
173                                         psf->write_int          = host_write_i2d ;
174                                         psf->write_float        = host_write_f2d ;
175                                         psf->write_double       = host_write_d ;
176                                         break ;
177
178                         case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) :
179                                         psf->float_endswap = SF_FALSE ;
180                                         psf->write_short        = host_write_s2d ;
181                                         psf->write_int          = host_write_i2d ;
182                                         psf->write_float        = host_write_f2d ;
183                                         psf->write_double       = host_write_d ;
184                                         break ;
185
186                         case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) :
187                                         psf->float_endswap = SF_TRUE ;
188                                         psf->write_short        = host_write_s2d ;
189                                         psf->write_int          = host_write_i2d ;
190                                         psf->write_float        = host_write_f2d ;
191                                         psf->write_double       = host_write_d ;
192                                         break ;
193
194                         case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) :
195                                         psf->float_endswap = SF_TRUE ;
196                                         psf->write_short        = host_write_s2d ;
197                                         psf->write_int          = host_write_i2d ;
198                                         psf->write_float        = host_write_f2d ;
199                                         psf->write_double       = host_write_d ;
200                                         break ;
201
202                         /* When the CPU is not IEEE compatible. */
203                         case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) :
204                                         psf->float_endswap = SF_FALSE ;
205                                         psf->write_short        = replace_write_s2d ;
206                                         psf->write_int          = replace_write_i2d ;
207                                         psf->write_float        = replace_write_f2d ;
208                                         psf->write_double       = replace_write_d ;
209                                         break ;
210
211                         case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) :
212                                         psf->float_endswap = SF_FALSE ;
213                                         psf->write_short        = replace_write_s2d ;
214                                         psf->write_int          = replace_write_i2d ;
215                                         psf->write_float        = replace_write_f2d ;
216                                         psf->write_double       = replace_write_d ;
217                                         break ;
218
219                         case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) :
220                                         psf->float_endswap = SF_TRUE ;
221                                         psf->write_short        = replace_write_s2d ;
222                                         psf->write_int          = replace_write_i2d ;
223                                         psf->write_float        = replace_write_f2d ;
224                                         psf->write_double       = replace_write_d ;
225                                         break ;
226
227                         case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) :
228                                         psf->float_endswap = SF_TRUE ;
229                                         psf->write_short        = replace_write_s2d ;
230                                         psf->write_int          = replace_write_i2d ;
231                                         psf->write_float        = replace_write_f2d ;
232                                         psf->write_double       = replace_write_d ;
233                                         break ;
234
235                         default : break ;
236                         } ;
237                 } ;
238
239         if (psf->filelength > psf->dataoffset)
240         {       psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset :
241                                                         psf->filelength - psf->dataoffset ;
242                 }
243         else
244                 psf->datalength = 0 ;
245
246         psf->sf.frames = psf->datalength / psf->blockwidth ;
247
248         return 0 ;
249 } /* double64_init */
250
251 /*----------------------------------------------------------------------------
252 ** From : http://www.hpcf.cam.ac.uk/fp_formats.html
253 **
254 ** 64 bit double precision layout (big endian)
255 **        Sign                          bit 0
256 **        Exponent                      bits 1-11
257 **        Mantissa                      bits 12-63
258 **        Exponent Offset       1023
259 **
260 **            double             single
261 **
262 ** +INF     7FF0000000000000     7F800000
263 ** -INF     FFF0000000000000     FF800000
264 **  NaN     7FF0000000000001     7F800001
265 **                to               to
266 **          7FFFFFFFFFFFFFFF     7FFFFFFF
267 **                and              and
268 **          FFF0000000000001     FF800001
269 **                to               to
270 **          FFFFFFFFFFFFFFFF     FFFFFFFF
271 ** +OVER    7FEFFFFFFFFFFFFF     7F7FFFFF
272 ** -OVER    FFEFFFFFFFFFFFFF     FF7FFFFF
273 ** +UNDER   0010000000000000     00800000
274 ** -UNDER   8010000000000000     80800000
275 */
276
277 double
278 double64_be_read (unsigned char *cptr)
279 {       int             exponent, negative, upper, lower ;
280         double  dvalue ;
281
282         negative = (cptr [0] & 0x80) ? 1 : 0 ;
283         exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ;
284
285         /* Might not have a 64 bit long, so load the mantissa into a double. */
286         upper = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ;
287         lower = (cptr [5] << 16) | (cptr [6] << 8) | cptr [7] ;
288
289         if (exponent == 0 && upper == 0 && lower == 0)
290                 return 0.0 ;
291
292         dvalue = upper + lower / ((double) 0x1000000) ;
293         dvalue += 0x10000000 ;
294
295         exponent = exponent - 0x3FF ;
296
297         dvalue = dvalue / ((double) 0x10000000) ;
298
299         if (negative)
300                 dvalue *= -1 ;
301
302         if (exponent > 0)
303                 dvalue *= (1 << exponent) ;
304         else if (exponent < 0)
305                 dvalue /= (1 << abs (exponent)) ;
306
307         return dvalue ;
308 } /* double64_be_read */
309
310 double
311 double64_le_read (unsigned char *cptr)
312 {       int             exponent, negative, upper, lower ;
313         double  dvalue ;
314
315         negative = (cptr [7] & 0x80) ? 1 : 0 ;
316         exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ;
317
318         /* Might not have a 64 bit long, so load the mantissa into a double. */
319         upper = ((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8) | cptr [3] ;
320         lower = (cptr [2] << 16) | (cptr [1] << 8) | cptr [0] ;
321
322         if (exponent == 0 && upper == 0 && lower == 0)
323                 return 0.0 ;
324
325         dvalue = upper + lower / ((double) 0x1000000) ;
326         dvalue += 0x10000000 ;
327
328         exponent = exponent - 0x3FF ;
329
330         dvalue = dvalue / ((double) 0x10000000) ;
331
332         if (negative)
333                 dvalue *= -1 ;
334
335         if (exponent > 0)
336                 dvalue *= (1 << exponent) ;
337         else if (exponent < 0)
338                 dvalue /= (1 << abs (exponent)) ;
339
340         return dvalue ;
341 } /* double64_le_read */
342
343 void
344 double64_be_write (double in, unsigned char *out)
345 {       int             exponent, mantissa ;
346
347         memset (out, 0, sizeof (double)) ;
348
349         if (fabs (in) < 1e-30)
350                 return ;
351
352         if (in < 0.0)
353         {       in *= -1.0 ;
354                 out [0] |= 0x80 ;
355                 } ;
356
357         in = frexp (in, &exponent) ;
358
359         exponent += 1022 ;
360
361         out [0] |= (exponent >> 4) & 0x7F ;
362         out [1] |= (exponent << 4) & 0xF0 ;
363
364         in *= 0x20000000 ;
365         mantissa = lrint (floor (in)) ;
366
367         out [1] |= (mantissa >> 24) & 0xF ;
368         out [2] = (mantissa >> 16) & 0xFF ;
369         out [3] = (mantissa >> 8) & 0xFF ;
370         out [4] = mantissa & 0xFF ;
371
372         in = fmod (in, 1.0) ;
373         in *= 0x1000000 ;
374         mantissa = lrint (floor (in)) ;
375
376         out [5] = (mantissa >> 16) & 0xFF ;
377         out [6] = (mantissa >> 8) & 0xFF ;
378         out [7] = mantissa & 0xFF ;
379
380         return ;
381 } /* double64_be_write */
382
383 void
384 double64_le_write (double in, unsigned char *out)
385 {       int             exponent, mantissa ;
386
387         memset (out, 0, sizeof (double)) ;
388
389         if (fabs (in) < 1e-30)
390                 return ;
391
392         if (in < 0.0)
393         {       in *= -1.0 ;
394                 out [7] |= 0x80 ;
395                 } ;
396
397         in = frexp (in, &exponent) ;
398
399         exponent += 1022 ;
400
401         out [7] |= (exponent >> 4) & 0x7F ;
402         out [6] |= (exponent << 4) & 0xF0 ;
403
404         in *= 0x20000000 ;
405         mantissa = lrint (floor (in)) ;
406
407         out [6] |= (mantissa >> 24) & 0xF ;
408         out [5] = (mantissa >> 16) & 0xFF ;
409         out [4] = (mantissa >> 8) & 0xFF ;
410         out [3] = mantissa & 0xFF ;
411
412         in = fmod (in, 1.0) ;
413         in *= 0x1000000 ;
414         mantissa = lrint (floor (in)) ;
415
416         out [2] = (mantissa >> 16) & 0xFF ;
417         out [1] = (mantissa >> 8) & 0xFF ;
418         out [0] = mantissa & 0xFF ;
419
420         return ;
421 } /* double64_le_write */
422
423 /*==============================================================================================
424 **      Private functions.
425 */
426
427 static void
428 double64_peak_update    (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx)
429 {       int     chan ;
430         int             k, position ;
431         float   fmaxval ;
432
433         for (chan = 0 ; chan < psf->sf.channels ; chan++)
434         {       fmaxval = fabs (buffer [chan]) ;
435                 position = 0 ;
436                 for (k = chan ; k < count ; k += psf->sf.channels)
437                         if (fmaxval < fabs (buffer [k]))
438                         {       fmaxval = fabs (buffer [k]) ;
439                                 position = k ;
440                                 } ;
441
442                 if (fmaxval > psf->peak_info->peaks [chan].value)
443                 {       psf->peak_info->peaks [chan].value = fmaxval ;
444                         psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ;
445                         } ;
446                 } ;
447
448         return ;
449 } /* double64_peak_update */
450
451 static int
452 double64_get_capability (SF_PRIVATE *psf)
453 {       union
454         {       double                  d ;
455                 int                             i [2] ;
456                 unsigned char   c [8] ;
457         } data ;
458
459         data.d = 1.234567890123456789 ; /* Some abitrary value. */
460
461         if (! psf->ieee_replace)
462         {       /* If this test is true ints and floats are compatible and little endian. */
463                 if (data.i [0] == 0x428c59fb && data.i [1] == 0x3ff3c0ca &&
464                         data.c [0] == 0xfb && data.c [2] == 0x8c && data.c [4] == 0xca && data.c [6] == 0xf3)
465                         return DOUBLE_CAN_RW_LE ;
466
467                 /* If this test is true ints and floats are compatible and big endian. */
468                 if ((data.i [0] == 0x3ff3c0ca && data.i [1] == 0x428c59fb) &&
469                         (data.c [0] == 0x3f && data.c [2] == 0xc0 && data.c [4] == 0x42 && data.c [6] == 0x59))
470                         return DOUBLE_CAN_RW_BE ;
471                 } ;
472
473         /* Doubles are broken. Don't expect reading or writing to be fast. */
474         psf_log_printf (psf, "Using IEEE replacement code for double.\n") ;
475
476         return (CPU_IS_LITTLE_ENDIAN) ? DOUBLE_BROKEN_LE : DOUBLE_BROKEN_BE ;
477 } /* double64_get_capability */
478
479 /*=======================================================================================
480 */
481
482 static inline void
483 d2s_array (const double *src, int count, short *dest, double scale)
484 {       while (--count >= 0)
485         {       dest [count] = lrint (scale * src [count]) ;
486                 } ;
487 } /* d2s_array */
488
489 static inline void
490 d2i_array (const double *src, int count, int *dest, double scale)
491 {       while (--count >= 0)
492         {       dest [count] = lrint (scale * src [count]) ;
493                 } ;
494 } /* d2i_array */
495
496 static inline void
497 d2f_array (const double *src, int count, float *dest)
498 {       while (--count >= 0)
499         {       dest [count] = src [count] ;
500                 } ;
501 } /* d2f_array */
502
503 static inline void
504 s2d_array (const short *src, double *dest, int count)
505 {       while (--count >= 0)
506         {       dest [count] = src [count] ;
507                 } ;
508 } /* s2d_array */
509
510 static inline void
511 i2d_array (const int *src, double *dest, int count)
512 {       while (--count >= 0)
513         {       dest [count] = src [count] ;
514                 } ;
515 } /* i2d_array */
516
517 static inline void
518 f2d_array (const float *src, double *dest, int count)
519 {       while (--count >= 0)
520         {       dest [count] = src [count] ;
521                 } ;
522 } /* f2d_array */
523
524 /*----------------------------------------------------------------------------------------------
525 */
526
527 static sf_count_t
528 host_read_d2s   (SF_PRIVATE *psf, short *ptr, sf_count_t len)
529 {       int                     bufferlen, readcount ;
530         sf_count_t      total = 0 ;
531         double          scale ;
532
533         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
534         scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
535
536         while (len > 0)
537         {       if (len < bufferlen)
538                         bufferlen = (int) len ;
539                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
540
541                 if (psf->float_endswap == SF_TRUE)
542                         endswap_double_array (psf->u.dbuf, readcount) ;
543
544                 d2s_array (psf->u.dbuf, readcount, ptr + total, scale) ;
545                 total += readcount ;
546                 len -= readcount ;
547                 if (readcount < bufferlen)
548                         break ;
549                 } ;
550
551         return total ;
552 } /* host_read_d2s */
553
554 static sf_count_t
555 host_read_d2i   (SF_PRIVATE *psf, int *ptr, sf_count_t len)
556 {       int                     bufferlen, readcount ;
557         sf_count_t      total = 0 ;
558         double          scale ;
559         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
560         scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
561
562         while (len > 0)
563         {       if (len < bufferlen)
564                         bufferlen = (int) len ;
565                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
566
567                 if (psf->float_endswap == SF_TRUE)
568                         endswap_double_array (psf->u.dbuf, bufferlen) ;
569
570                 d2i_array (psf->u.dbuf, readcount, ptr + total, scale) ;
571                 total += readcount ;
572                 len -= readcount ;
573                 if (readcount < bufferlen)
574                         break ;
575                 } ;
576
577         return total ;
578 } /* host_read_d2i */
579
580 static sf_count_t
581 host_read_d2f   (SF_PRIVATE *psf, float *ptr, sf_count_t len)
582 {       int                     bufferlen, readcount ;
583         sf_count_t      total = 0 ;
584
585         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
586
587         while (len > 0)
588         {       if (len < bufferlen)
589                         bufferlen = (int) len ;
590                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
591
592                 if (psf->float_endswap == SF_TRUE)
593                         endswap_double_array (psf->u.dbuf, bufferlen) ;
594
595                 d2f_array (psf->u.dbuf, readcount, ptr + total) ;
596                 total += readcount ;
597                 len -= readcount ;
598                 if (readcount < bufferlen)
599                         break ;
600                 } ;
601
602         return total ;
603 } /* host_read_d2f */
604
605 static sf_count_t
606 host_read_d     (SF_PRIVATE *psf, double *ptr, sf_count_t len)
607 {       int                     bufferlen ;
608         sf_count_t      readcount, total = 0 ;
609
610         readcount = psf_fread (ptr, sizeof (double), len, psf) ;
611
612         if (psf->float_endswap != SF_TRUE)
613                 return readcount ;
614
615         /* If the read length was sensible, endswap output in one go. */
616         if (readcount < SENSIBLE_LEN)
617         {       endswap_double_array (ptr, readcount) ;
618                 return readcount ;
619                 } ;
620
621         bufferlen = SENSIBLE_LEN ;
622         while (len > 0)
623         {       if (len < bufferlen)
624                         bufferlen = (int) len ;
625
626                 endswap_double_array (ptr + total, bufferlen) ;
627
628                 total += bufferlen ;
629                 len -= bufferlen ;
630                 } ;
631
632         return total ;
633 } /* host_read_d */
634
635 static sf_count_t
636 host_write_s2d  (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
637 {       int                     bufferlen, writecount ;
638         sf_count_t      total = 0 ;
639
640         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
641
642         while (len > 0)
643         {       if (len < bufferlen)
644                         bufferlen = (int) len ;
645
646                 s2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
647
648                 if (psf->peak_info)
649                         double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
650
651                 if (psf->float_endswap == SF_TRUE)
652                         endswap_double_array (psf->u.dbuf, bufferlen) ;
653
654                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
655                 total += writecount ;
656                 if (writecount < bufferlen)
657                         break ;
658                 len -= writecount ;
659                 } ;
660
661         return total ;
662 } /* host_write_s2d */
663
664 static sf_count_t
665 host_write_i2d  (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
666 {       int                     bufferlen, writecount ;
667         sf_count_t      total = 0 ;
668
669         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
670
671         while (len > 0)
672         {       if (len < bufferlen)
673                         bufferlen = (int) len ;
674                 i2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
675
676                 if (psf->peak_info)
677                         double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
678
679                 if (psf->float_endswap == SF_TRUE)
680                         endswap_double_array (psf->u.dbuf, bufferlen) ;
681
682                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
683                 total += writecount ;
684                 if (writecount < bufferlen)
685                         break ;
686                 len -= writecount ;
687                 } ;
688
689         return total ;
690 } /* host_write_i2d */
691
692 static sf_count_t
693 host_write_f2d  (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
694 {       int                     bufferlen, writecount ;
695         sf_count_t      total = 0 ;
696
697         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
698
699         while (len > 0)
700         {       if (len < bufferlen)
701                         bufferlen = (int) len ;
702                 f2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
703
704                 if (psf->peak_info)
705                         double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
706
707                 if (psf->float_endswap == SF_TRUE)
708                         endswap_double_array (psf->u.dbuf, bufferlen) ;
709
710                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
711                 total += writecount ;
712                 if (writecount < bufferlen)
713                         break ;
714                 len -= writecount ;
715                 } ;
716
717         return total ;
718 } /* host_write_f2d */
719
720 static sf_count_t
721 host_write_d    (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
722 {       int                     bufferlen, writecount ;
723         sf_count_t      total = 0 ;
724
725         if (psf->peak_info)
726                 double64_peak_update (psf, ptr, len, 0) ;
727
728         if (psf->float_endswap != SF_TRUE)
729                 return psf_fwrite (ptr, sizeof (double), len, psf) ;
730
731         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
732
733         while (len > 0)
734         {       if (len < bufferlen)
735                         bufferlen = (int) len ;
736
737                 endswap_double_copy (psf->u.dbuf, ptr + total, bufferlen) ;
738
739                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
740                 total += writecount ;
741                 if (writecount < bufferlen)
742                         break ;
743                 len -= writecount ;
744                 } ;
745
746         return total ;
747 } /* host_write_d */
748
749 /*=======================================================================================
750 */
751
752 static sf_count_t
753 replace_read_d2s        (SF_PRIVATE *psf, short *ptr, sf_count_t len)
754 {       int                     bufferlen, readcount ;
755         sf_count_t      total = 0 ;
756         double          scale ;
757
758         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
759         scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ;
760
761         while (len > 0)
762         {       if (len < bufferlen)
763                         bufferlen = (int) len ;
764                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
765
766                 if (psf->float_endswap == SF_TRUE)
767                         endswap_double_array (psf->u.dbuf, bufferlen) ;
768
769                 d2bd_read (psf->u.dbuf, bufferlen) ;
770
771                 d2s_array (psf->u.dbuf, readcount, ptr + total, scale) ;
772                 total += readcount ;
773                 if (readcount < bufferlen)
774                         break ;
775                 len -= readcount ;
776                 } ;
777
778         return total ;
779 } /* replace_read_d2s */
780
781 static sf_count_t
782 replace_read_d2i        (SF_PRIVATE *psf, int *ptr, sf_count_t len)
783 {       int                     bufferlen, readcount ;
784         sf_count_t      total = 0 ;
785         double          scale ;
786
787         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
788         scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ;
789
790         while (len > 0)
791         {       if (len < bufferlen)
792                         bufferlen = (int) len ;
793                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
794
795                 if (psf->float_endswap == SF_TRUE)
796                         endswap_double_array (psf->u.dbuf, bufferlen) ;
797
798                 d2bd_read (psf->u.dbuf, bufferlen) ;
799
800                 d2i_array (psf->u.dbuf, readcount, ptr + total, scale) ;
801                 total += readcount ;
802                 if (readcount < bufferlen)
803                         break ;
804                 len -= readcount ;
805                 } ;
806
807         return total ;
808 } /* replace_read_d2i */
809
810 static sf_count_t
811 replace_read_d2f        (SF_PRIVATE *psf, float *ptr, sf_count_t len)
812 {       int                     bufferlen, readcount ;
813         sf_count_t      total = 0 ;
814
815         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
816
817         while (len > 0)
818         {       if (len < bufferlen)
819                         bufferlen = (int) len ;
820                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
821
822                 if (psf->float_endswap == SF_TRUE)
823                         endswap_double_array (psf->u.dbuf, bufferlen) ;
824
825                 d2bd_read (psf->u.dbuf, bufferlen) ;
826
827                 memcpy (ptr + total, psf->u.dbuf, bufferlen * sizeof (double)) ;
828
829                 total += readcount ;
830                 if (readcount < bufferlen)
831                         break ;
832                 len -= readcount ;
833                 } ;
834
835         return total ;
836 } /* replace_read_d2f */
837
838 static sf_count_t
839 replace_read_d  (SF_PRIVATE *psf, double *ptr, sf_count_t len)
840 {       int                     bufferlen, readcount ;
841         sf_count_t      total = 0 ;
842
843         /* FIXME : This is probably nowhere near optimal. */
844         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
845
846         while (len > 0)
847         {       if (len < bufferlen)
848                         bufferlen = (int) len ;
849                 readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
850
851                 if (psf->float_endswap == SF_TRUE)
852                         endswap_double_array (psf->u.dbuf, readcount) ;
853
854                 d2bd_read (psf->u.dbuf, readcount) ;
855
856                 memcpy (ptr + total, psf->u.dbuf, readcount * sizeof (double)) ;
857
858                 total += readcount ;
859                 if (readcount < bufferlen)
860                         break ;
861                 len -= readcount ;
862                 } ;
863
864         return total ;
865 } /* replace_read_d */
866
867 static sf_count_t
868 replace_write_s2d       (SF_PRIVATE *psf, const short *ptr, sf_count_t len)
869 {       int                     bufferlen, writecount ;
870         sf_count_t      total = 0 ;
871
872         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
873
874         while (len > 0)
875         {       if (len < bufferlen)
876                         bufferlen = (int) len ;
877                 s2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
878
879                 if (psf->peak_info)
880                         double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
881
882                 bd2d_write (psf->u.dbuf, bufferlen) ;
883
884                 if (psf->float_endswap == SF_TRUE)
885                         endswap_double_array (psf->u.dbuf, bufferlen) ;
886
887                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
888                 total += writecount ;
889                 if (writecount < bufferlen)
890                         break ;
891                 len -= writecount ;
892                 } ;
893
894         return total ;
895 } /* replace_write_s2d */
896
897 static sf_count_t
898 replace_write_i2d       (SF_PRIVATE *psf, const int *ptr, sf_count_t len)
899 {       int                     bufferlen, writecount ;
900         sf_count_t      total = 0 ;
901
902         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
903
904         while (len > 0)
905         {       if (len < bufferlen)
906                         bufferlen = (int) len ;
907                 i2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
908
909                 if (psf->peak_info)
910                         double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ;
911
912                 bd2d_write (psf->u.dbuf, bufferlen) ;
913
914                 if (psf->float_endswap == SF_TRUE)
915                         endswap_double_array (psf->u.dbuf, bufferlen) ;
916
917                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
918                 total += writecount ;
919                 if (writecount < bufferlen)
920                         break ;
921                 len -= writecount ;
922                 } ;
923
924         return total ;
925 } /* replace_write_i2d */
926
927 static sf_count_t
928 replace_write_f2d       (SF_PRIVATE *psf, const float *ptr, sf_count_t len)
929 {       int                     bufferlen, writecount ;
930         sf_count_t      total = 0 ;
931
932         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
933
934         while (len > 0)
935         {       if (len < bufferlen)
936                         bufferlen = (int) len ;
937                 f2d_array (ptr + total, psf->u.dbuf, bufferlen) ;
938
939                 bd2d_write (psf->u.dbuf, bufferlen) ;
940
941                 if (psf->float_endswap == SF_TRUE)
942                         endswap_double_array (psf->u.dbuf, bufferlen) ;
943
944                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
945                 total += writecount ;
946                 if (writecount < bufferlen)
947                         break ;
948                 len -= writecount ;
949                 } ;
950
951         return total ;
952 } /* replace_write_f2d */
953
954 static sf_count_t
955 replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len)
956 {       int                     bufferlen, writecount ;
957         sf_count_t      total = 0 ;
958
959         /* FIXME : This is probably nowhere near optimal. */
960         if (psf->peak_info)
961                 double64_peak_update (psf, ptr, len, 0) ;
962
963         bufferlen = ARRAY_LEN (psf->u.dbuf) ;
964
965         while (len > 0)
966         {       if (len < bufferlen)
967                         bufferlen = (int) len ;
968
969                 memcpy (psf->u.dbuf, ptr + total, bufferlen * sizeof (double)) ;
970
971                 bd2d_write (psf->u.dbuf, bufferlen) ;
972
973                 if (psf->float_endswap == SF_TRUE)
974                         endswap_double_array (psf->u.dbuf, bufferlen) ;
975
976                 writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ;
977                 total += writecount ;
978                 if (writecount < bufferlen)
979                         break ;
980                 len -= writecount ;
981                 } ;
982
983         return total ;
984 } /* replace_write_d */
985
986 /*----------------------------------------------------------------------------------------------
987 */
988
989 static void
990 d2bd_read (double *buffer, int count)
991 {       while (--count >= 0)
992         {       buffer [count] = DOUBLE64_READ ((unsigned char *) (buffer + count)) ;
993                 } ;
994 } /* d2bd_read */
995
996 static void
997 bd2d_write (double *buffer, int count)
998 {       while (--count >= 0)
999         {       DOUBLE64_WRITE (buffer [count], (unsigned char*) (buffer + count)) ;
1000                 } ;
1001 } /* bd2d_write */
1002
1003 /*
1004 ** Do not edit or modify anything in this comment block.
1005 ** The arch-tag line is a file identity tag for the GNU Arch
1006 ** revision control system.
1007 **
1008 ** arch-tag: 4ee243b7-8c7a-469b-869c-e9aa0ee3b77f
1009 */