| /* |
| ** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com> |
| ** |
| ** This program is free software; you can redistribute it and/or modify |
| ** it under the terms of the GNU Lesser General Public License as published by |
| ** the Free Software Foundation; either version 2.1 of the License, or |
| ** (at your option) any later version. |
| ** |
| ** This program is distributed in the hope that it will be useful, |
| ** but WITHOUT ANY WARRANTY; without even the implied warranty of |
| ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| ** GNU Lesser General Public License for more details. |
| ** |
| ** You should have received a copy of the GNU Lesser General Public License |
| ** along with this program; if not, write to the Free Software |
| ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| */ |
| |
| #include "sfconfig.h" |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <limits.h> |
| #include <math.h> |
| |
| #include "sndfile.h" |
| #include "sfendian.h" |
| #include "common.h" |
| |
| #if CPU_IS_LITTLE_ENDIAN |
| #define DOUBLE64_READ double64_le_read |
| #define DOUBLE64_WRITE double64_le_write |
| #elif CPU_IS_BIG_ENDIAN |
| #define DOUBLE64_READ double64_be_read |
| #define DOUBLE64_WRITE double64_be_write |
| #endif |
| |
| /* A 32 number which will not overflow when multiplied by sizeof (double). */ |
| #define SENSIBLE_LEN (0x8000000) |
| |
| /*-------------------------------------------------------------------------------------------- |
| ** Processor floating point capabilities. double64_get_capability () returns one of the |
| ** latter three values. |
| */ |
| |
| enum |
| { DOUBLE_UNKNOWN = 0x00, |
| DOUBLE_CAN_RW_LE = 0x23, |
| DOUBLE_CAN_RW_BE = 0x34, |
| DOUBLE_BROKEN_LE = 0x45, |
| DOUBLE_BROKEN_BE = 0x56 |
| } ; |
| |
| /*-------------------------------------------------------------------------------------------- |
| ** Prototypes for private functions. |
| */ |
| |
| static sf_count_t host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; |
| static sf_count_t host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; |
| static sf_count_t host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; |
| static sf_count_t host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; |
| |
| static sf_count_t host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; |
| static sf_count_t host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; |
| static sf_count_t host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; |
| static sf_count_t host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; |
| |
| static void double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) ; |
| |
| static int double64_get_capability (SF_PRIVATE *psf) ; |
| |
| static sf_count_t replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ; |
| static sf_count_t replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ; |
| static sf_count_t replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ; |
| static sf_count_t replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ; |
| |
| static sf_count_t replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) ; |
| static sf_count_t replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) ; |
| static sf_count_t replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) ; |
| static sf_count_t replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) ; |
| |
| static void d2bd_read (double *buffer, int count) ; |
| static void bd2d_write (double *buffer, int count) ; |
| |
| /*-------------------------------------------------------------------------------------------- |
| ** Exported functions. |
| */ |
| |
| int |
| double64_init (SF_PRIVATE *psf) |
| { static int double64_caps ; |
| |
| double64_caps = double64_get_capability (psf) ; |
| |
| psf->blockwidth = sizeof (double) * psf->sf.channels ; |
| |
| if (psf->file.mode == SFM_READ || psf->file.mode == SFM_RDWR) |
| { switch (psf->endian + double64_caps) |
| { case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->read_short = host_read_d2s ; |
| psf->read_int = host_read_d2i ; |
| psf->read_float = host_read_d2f ; |
| psf->read_double = host_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->read_short = host_read_d2s ; |
| psf->read_int = host_read_d2i ; |
| psf->read_float = host_read_d2f ; |
| psf->read_double = host_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->read_short = host_read_d2s ; |
| psf->read_int = host_read_d2i ; |
| psf->read_float = host_read_d2f ; |
| psf->read_double = host_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->read_short = host_read_d2s ; |
| psf->read_int = host_read_d2i ; |
| psf->read_float = host_read_d2f ; |
| psf->read_double = host_read_d ; |
| break ; |
| |
| /* When the CPU is not IEEE compatible. */ |
| case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->read_short = replace_read_d2s ; |
| psf->read_int = replace_read_d2i ; |
| psf->read_float = replace_read_d2f ; |
| psf->read_double = replace_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->read_short = replace_read_d2s ; |
| psf->read_int = replace_read_d2i ; |
| psf->read_float = replace_read_d2f ; |
| psf->read_double = replace_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->read_short = replace_read_d2s ; |
| psf->read_int = replace_read_d2i ; |
| psf->read_float = replace_read_d2f ; |
| psf->read_double = replace_read_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->read_short = replace_read_d2s ; |
| psf->read_int = replace_read_d2i ; |
| psf->read_float = replace_read_d2f ; |
| psf->read_double = replace_read_d ; |
| break ; |
| |
| default : break ; |
| } ; |
| } ; |
| |
| if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR) |
| { switch (psf->endian + double64_caps) |
| { case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_LE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->write_short = host_write_s2d ; |
| psf->write_int = host_write_i2d ; |
| psf->write_float = host_write_f2d ; |
| psf->write_double = host_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_BE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->write_short = host_write_s2d ; |
| psf->write_int = host_write_i2d ; |
| psf->write_float = host_write_f2d ; |
| psf->write_double = host_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_CAN_RW_LE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->write_short = host_write_s2d ; |
| psf->write_int = host_write_i2d ; |
| psf->write_float = host_write_f2d ; |
| psf->write_double = host_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_CAN_RW_BE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->write_short = host_write_s2d ; |
| psf->write_int = host_write_i2d ; |
| psf->write_float = host_write_f2d ; |
| psf->write_double = host_write_d ; |
| break ; |
| |
| /* When the CPU is not IEEE compatible. */ |
| case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_LE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->write_short = replace_write_s2d ; |
| psf->write_int = replace_write_i2d ; |
| psf->write_float = replace_write_f2d ; |
| psf->write_double = replace_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_BROKEN_BE) : |
| psf->data_endswap = SF_FALSE ; |
| psf->write_short = replace_write_s2d ; |
| psf->write_int = replace_write_i2d ; |
| psf->write_float = replace_write_f2d ; |
| psf->write_double = replace_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_BIG + DOUBLE_BROKEN_LE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->write_short = replace_write_s2d ; |
| psf->write_int = replace_write_i2d ; |
| psf->write_float = replace_write_f2d ; |
| psf->write_double = replace_write_d ; |
| break ; |
| |
| case (SF_ENDIAN_LITTLE + DOUBLE_BROKEN_BE) : |
| psf->data_endswap = SF_TRUE ; |
| psf->write_short = replace_write_s2d ; |
| psf->write_int = replace_write_i2d ; |
| psf->write_float = replace_write_f2d ; |
| psf->write_double = replace_write_d ; |
| break ; |
| |
| default : break ; |
| } ; |
| } ; |
| |
| if (psf->filelength > psf->dataoffset) |
| { psf->datalength = (psf->dataend > 0) ? psf->dataend - psf->dataoffset : |
| psf->filelength - psf->dataoffset ; |
| } |
| else |
| psf->datalength = 0 ; |
| |
| psf->sf.frames = psf->datalength / psf->blockwidth ; |
| |
| return 0 ; |
| } /* double64_init */ |
| |
| /*---------------------------------------------------------------------------- |
| ** From : http://www.hpcf.cam.ac.uk/fp_formats.html |
| ** |
| ** 64 bit double precision layout (big endian) |
| ** Sign bit 0 |
| ** Exponent bits 1-11 |
| ** Mantissa bits 12-63 |
| ** Exponent Offset 1023 |
| ** |
| ** double single |
| ** |
| ** +INF 7FF0000000000000 7F800000 |
| ** -INF FFF0000000000000 FF800000 |
| ** NaN 7FF0000000000001 7F800001 |
| ** to to |
| ** 7FFFFFFFFFFFFFFF 7FFFFFFF |
| ** and and |
| ** FFF0000000000001 FF800001 |
| ** to to |
| ** FFFFFFFFFFFFFFFF FFFFFFFF |
| ** +OVER 7FEFFFFFFFFFFFFF 7F7FFFFF |
| ** -OVER FFEFFFFFFFFFFFFF FF7FFFFF |
| ** +UNDER 0010000000000000 00800000 |
| ** -UNDER 8010000000000000 80800000 |
| */ |
| |
| double |
| double64_be_read (unsigned char *cptr) |
| { int exponent, negative, upper, lower ; |
| double dvalue ; |
| |
| negative = (cptr [0] & 0x80) ? 1 : 0 ; |
| exponent = ((cptr [0] & 0x7F) << 4) | ((cptr [1] >> 4) & 0xF) ; |
| |
| /* Might not have a 64 bit long, so load the mantissa into a double. */ |
| upper = (((cptr [1] & 0xF) << 24) | (cptr [2] << 16) | (cptr [3] << 8) | cptr [4]) ; |
| lower = (cptr [5] << 16) | (cptr [6] << 8) | cptr [7] ; |
| |
| if (exponent == 0 && upper == 0 && lower == 0) |
| return 0.0 ; |
| |
| dvalue = upper + lower / ((double) 0x1000000) ; |
| dvalue += 0x10000000 ; |
| |
| exponent = exponent - 0x3FF ; |
| |
| dvalue = dvalue / ((double) 0x10000000) ; |
| |
| if (negative) |
| dvalue *= -1 ; |
| |
| if (exponent > 0) |
| dvalue *= pow (2.0, exponent) ; |
| else if (exponent < 0) |
| dvalue /= pow (2.0, abs (exponent)) ; |
| |
| return dvalue ; |
| } /* double64_be_read */ |
| |
| double |
| double64_le_read (unsigned char *cptr) |
| { int exponent, negative, upper, lower ; |
| double dvalue ; |
| |
| negative = (cptr [7] & 0x80) ? 1 : 0 ; |
| exponent = ((cptr [7] & 0x7F) << 4) | ((cptr [6] >> 4) & 0xF) ; |
| |
| /* Might not have a 64 bit long, so load the mantissa into a double. */ |
| upper = ((cptr [6] & 0xF) << 24) | (cptr [5] << 16) | (cptr [4] << 8) | cptr [3] ; |
| lower = (cptr [2] << 16) | (cptr [1] << 8) | cptr [0] ; |
| |
| if (exponent == 0 && upper == 0 && lower == 0) |
| return 0.0 ; |
| |
| dvalue = upper + lower / ((double) 0x1000000) ; |
| dvalue += 0x10000000 ; |
| |
| exponent = exponent - 0x3FF ; |
| |
| dvalue = dvalue / ((double) 0x10000000) ; |
| |
| if (negative) |
| dvalue *= -1 ; |
| |
| if (exponent > 0) |
| dvalue *= pow (2.0, exponent) ; |
| else if (exponent < 0) |
| dvalue /= pow (2.0, abs (exponent)) ; |
| |
| return dvalue ; |
| } /* double64_le_read */ |
| |
| void |
| double64_be_write (double in, unsigned char *out) |
| { int exponent, mantissa ; |
| |
| memset (out, 0, sizeof (double)) ; |
| |
| if (fabs (in) < 1e-30) |
| return ; |
| |
| if (in < 0.0) |
| { in *= -1.0 ; |
| out [0] |= 0x80 ; |
| } ; |
| |
| in = frexp (in, &exponent) ; |
| |
| exponent += 1022 ; |
| |
| out [0] |= (exponent >> 4) & 0x7F ; |
| out [1] |= (exponent << 4) & 0xF0 ; |
| |
| in *= 0x20000000 ; |
| mantissa = lrint (floor (in)) ; |
| |
| out [1] |= (mantissa >> 24) & 0xF ; |
| out [2] = (mantissa >> 16) & 0xFF ; |
| out [3] = (mantissa >> 8) & 0xFF ; |
| out [4] = mantissa & 0xFF ; |
| |
| in = fmod (in, 1.0) ; |
| in *= 0x1000000 ; |
| mantissa = lrint (floor (in)) ; |
| |
| out [5] = (mantissa >> 16) & 0xFF ; |
| out [6] = (mantissa >> 8) & 0xFF ; |
| out [7] = mantissa & 0xFF ; |
| |
| return ; |
| } /* double64_be_write */ |
| |
| void |
| double64_le_write (double in, unsigned char *out) |
| { int exponent, mantissa ; |
| |
| memset (out, 0, sizeof (double)) ; |
| |
| if (fabs (in) < 1e-30) |
| return ; |
| |
| if (in < 0.0) |
| { in *= -1.0 ; |
| out [7] |= 0x80 ; |
| } ; |
| |
| in = frexp (in, &exponent) ; |
| |
| exponent += 1022 ; |
| |
| out [7] |= (exponent >> 4) & 0x7F ; |
| out [6] |= (exponent << 4) & 0xF0 ; |
| |
| in *= 0x20000000 ; |
| mantissa = lrint (floor (in)) ; |
| |
| out [6] |= (mantissa >> 24) & 0xF ; |
| out [5] = (mantissa >> 16) & 0xFF ; |
| out [4] = (mantissa >> 8) & 0xFF ; |
| out [3] = mantissa & 0xFF ; |
| |
| in = fmod (in, 1.0) ; |
| in *= 0x1000000 ; |
| mantissa = lrint (floor (in)) ; |
| |
| out [2] = (mantissa >> 16) & 0xFF ; |
| out [1] = (mantissa >> 8) & 0xFF ; |
| out [0] = mantissa & 0xFF ; |
| |
| return ; |
| } /* double64_le_write */ |
| |
| /*============================================================================================== |
| ** Private functions. |
| */ |
| |
| static void |
| double64_peak_update (SF_PRIVATE *psf, const double *buffer, int count, sf_count_t indx) |
| { int chan ; |
| int k, position ; |
| float fmaxval ; |
| |
| for (chan = 0 ; chan < psf->sf.channels ; chan++) |
| { fmaxval = fabs (buffer [chan]) ; |
| position = 0 ; |
| for (k = chan ; k < count ; k += psf->sf.channels) |
| if (fmaxval < fabs (buffer [k])) |
| { fmaxval = fabs (buffer [k]) ; |
| position = k ; |
| } ; |
| |
| if (fmaxval > psf->peak_info->peaks [chan].value) |
| { psf->peak_info->peaks [chan].value = fmaxval ; |
| psf->peak_info->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; |
| } ; |
| } ; |
| |
| return ; |
| } /* double64_peak_update */ |
| |
| static int |
| double64_get_capability (SF_PRIVATE *psf) |
| { union |
| { double d ; |
| unsigned char c [8] ; |
| } data ; |
| |
| data.d = 1.234567890123456789 ; /* Some abitrary value. */ |
| |
| if (! psf->ieee_replace) |
| { /* If this test is true ints and floats are compatible and little endian. */ |
| if (data.c [0] == 0xfb && data.c [1] == 0x59 && data.c [2] == 0x8c && data.c [3] == 0x42 && |
| data.c [4] == 0xca && data.c [5] == 0xc0 && data.c [6] == 0xf3 && data.c [7] == 0x3f) |
| return DOUBLE_CAN_RW_LE ; |
| |
| /* If this test is true ints and floats are compatible and big endian. */ |
| if (data.c [0] == 0x3f && data.c [1] == 0xf3 && data.c [2] == 0xc0 && data.c [3] == 0xca && |
| data.c [4] == 0x42 && data.c [5] == 0x8c && data.c [6] == 0x59 && data.c [7] == 0xfb) |
| return DOUBLE_CAN_RW_BE ; |
| } ; |
| |
| /* Doubles are broken. Don't expect reading or writing to be fast. */ |
| psf_log_printf (psf, "Using IEEE replacement code for double.\n") ; |
| |
| return (CPU_IS_LITTLE_ENDIAN) ? DOUBLE_BROKEN_LE : DOUBLE_BROKEN_BE ; |
| } /* double64_get_capability */ |
| |
| /*======================================================================================= |
| */ |
| |
| static void |
| d2s_array (const double *src, int count, short *dest, double scale) |
| { while (--count >= 0) |
| { dest [count] = lrint (scale * src [count]) ; |
| } ; |
| } /* d2s_array */ |
| |
| static void |
| d2s_clip_array (const double *src, int count, short *dest, double scale) |
| { while (--count >= 0) |
| { double tmp = scale * src [count] ; |
| |
| if (CPU_CLIPS_POSITIVE == 0 && tmp > 32767.0) |
| dest [count] = SHRT_MAX ; |
| else if (CPU_CLIPS_NEGATIVE == 0 && tmp < -32768.0) |
| dest [count] = SHRT_MIN ; |
| else |
| dest [count] = lrint (tmp) ; |
| } ; |
| } /* d2s_clip_array */ |
| |
| static void |
| d2i_array (const double *src, int count, int *dest, double scale) |
| { while (--count >= 0) |
| { dest [count] = lrint (scale * src [count]) ; |
| } ; |
| } /* d2i_array */ |
| |
| static void |
| d2i_clip_array (const double *src, int count, int *dest, double scale) |
| { while (--count >= 0) |
| { float tmp = scale * src [count] ; |
| |
| if (CPU_CLIPS_POSITIVE == 0 && tmp > (1.0 * INT_MAX)) |
| dest [count] = INT_MAX ; |
| else if (CPU_CLIPS_NEGATIVE == 0 && tmp < (-1.0 * INT_MAX)) |
| dest [count] = INT_MIN ; |
| else |
| dest [count] = lrint (tmp) ; |
| } ; |
| } /* d2i_clip_array */ |
| |
| static inline void |
| d2f_array (const double *src, int count, float *dest) |
| { while (--count >= 0) |
| { dest [count] = src [count] ; |
| } ; |
| } /* d2f_array */ |
| |
| static inline void |
| s2d_array (const short *src, double *dest, int count, double scale) |
| { while (--count >= 0) |
| { dest [count] = scale * src [count] ; |
| } ; |
| } /* s2d_array */ |
| |
| static inline void |
| i2d_array (const int *src, double *dest, int count, double scale) |
| { while (--count >= 0) |
| { dest [count] = scale * src [count] ; |
| } ; |
| } /* i2d_array */ |
| |
| static inline void |
| f2d_array (const float *src, double *dest, int count) |
| { while (--count >= 0) |
| { dest [count] = src [count] ; |
| } ; |
| } /* f2d_array */ |
| |
| /*---------------------------------------------------------------------------------------------- |
| */ |
| |
| static sf_count_t |
| host_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) |
| { void (*convert) (const double *, int, short *, double) ; |
| int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| convert = (psf->add_clipping) ? d2s_clip_array : d2s_array ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, readcount) ; |
| |
| convert (psf->u.dbuf, readcount, ptr + total, scale) ; |
| total += readcount ; |
| len -= readcount ; |
| if (readcount < bufferlen) |
| break ; |
| } ; |
| |
| return total ; |
| } /* host_read_d2s */ |
| |
| static sf_count_t |
| host_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) |
| { void (*convert) (const double *, int, int *, double) ; |
| int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| convert = (psf->add_clipping) ? d2i_clip_array : d2i_array ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| convert (psf->u.dbuf, readcount, ptr + total, scale) ; |
| total += readcount ; |
| len -= readcount ; |
| if (readcount < bufferlen) |
| break ; |
| } ; |
| |
| return total ; |
| } /* host_read_d2i */ |
| |
| static sf_count_t |
| host_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) |
| { int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| d2f_array (psf->u.dbuf, readcount, ptr + total) ; |
| total += readcount ; |
| len -= readcount ; |
| if (readcount < bufferlen) |
| break ; |
| } ; |
| |
| return total ; |
| } /* host_read_d2f */ |
| |
| static sf_count_t |
| host_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) |
| { int bufferlen ; |
| sf_count_t readcount, total = 0 ; |
| |
| readcount = psf_fread (ptr, sizeof (double), len, psf) ; |
| |
| if (psf->data_endswap != SF_TRUE) |
| return readcount ; |
| |
| /* If the read length was sensible, endswap output in one go. */ |
| if (readcount < SENSIBLE_LEN) |
| { endswap_double_array (ptr, readcount) ; |
| return readcount ; |
| } ; |
| |
| bufferlen = SENSIBLE_LEN ; |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| |
| endswap_double_array (ptr + total, bufferlen) ; |
| |
| total += bufferlen ; |
| len -= bufferlen ; |
| } ; |
| |
| return total ; |
| } /* host_read_d */ |
| |
| static sf_count_t |
| host_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| |
| s2d_array (ptr + total, psf->u.dbuf, bufferlen, scale) ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* host_write_s2d */ |
| |
| static sf_count_t |
| host_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| i2d_array (ptr + total, psf->u.dbuf, bufferlen, scale) ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* host_write_i2d */ |
| |
| static sf_count_t |
| host_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| f2d_array (ptr + total, psf->u.dbuf, bufferlen) ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* host_write_f2d */ |
| |
| static sf_count_t |
| host_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, ptr, len, 0) ; |
| |
| if (psf->data_endswap != SF_TRUE) |
| return psf_fwrite (ptr, sizeof (double), len, psf) ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| |
| endswap_double_copy (psf->u.dbuf, ptr + total, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* host_write_d */ |
| |
| /*======================================================================================= |
| */ |
| |
| static sf_count_t |
| replace_read_d2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) |
| { int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFF / psf->float_max ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| d2bd_read (psf->u.dbuf, bufferlen) ; |
| |
| d2s_array (psf->u.dbuf, readcount, ptr + total, scale) ; |
| total += readcount ; |
| if (readcount < bufferlen) |
| break ; |
| len -= readcount ; |
| } ; |
| |
| return total ; |
| } /* replace_read_d2s */ |
| |
| static sf_count_t |
| replace_read_d2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) |
| { int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| scale = (psf->float_int_mult == 0) ? 1.0 : 0x7FFFFFFF / psf->float_max ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| d2bd_read (psf->u.dbuf, bufferlen) ; |
| |
| d2i_array (psf->u.dbuf, readcount, ptr + total, scale) ; |
| total += readcount ; |
| if (readcount < bufferlen) |
| break ; |
| len -= readcount ; |
| } ; |
| |
| return total ; |
| } /* replace_read_d2i */ |
| |
| static sf_count_t |
| replace_read_d2f (SF_PRIVATE *psf, float *ptr, sf_count_t len) |
| { int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| d2bd_read (psf->u.dbuf, bufferlen) ; |
| |
| memcpy (ptr + total, psf->u.dbuf, bufferlen * sizeof (double)) ; |
| |
| total += readcount ; |
| if (readcount < bufferlen) |
| break ; |
| len -= readcount ; |
| } ; |
| |
| return total ; |
| } /* replace_read_d2f */ |
| |
| static sf_count_t |
| replace_read_d (SF_PRIVATE *psf, double *ptr, sf_count_t len) |
| { int bufferlen, readcount ; |
| sf_count_t total = 0 ; |
| |
| /* FIXME : This is probably nowhere near optimal. */ |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| readcount = psf_fread (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, readcount) ; |
| |
| d2bd_read (psf->u.dbuf, readcount) ; |
| |
| memcpy (ptr + total, psf->u.dbuf, readcount * sizeof (double)) ; |
| |
| total += readcount ; |
| if (readcount < bufferlen) |
| break ; |
| len -= readcount ; |
| } ; |
| |
| return total ; |
| } /* replace_read_d */ |
| |
| static sf_count_t |
| replace_write_s2d (SF_PRIVATE *psf, const short *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / 0x8000 ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| s2d_array (ptr + total, psf->u.dbuf, bufferlen, scale) ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; |
| |
| bd2d_write (psf->u.dbuf, bufferlen) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* replace_write_s2d */ |
| |
| static sf_count_t |
| replace_write_i2d (SF_PRIVATE *psf, const int *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| double scale ; |
| |
| scale = (psf->scale_int_float == 0) ? 1.0 : 1.0 / (8.0 * 0x10000000) ; |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| i2d_array (ptr + total, psf->u.dbuf, bufferlen, scale) ; |
| |
| if (psf->peak_info) |
| double64_peak_update (psf, psf->u.dbuf, bufferlen, total / psf->sf.channels) ; |
| |
| bd2d_write (psf->u.dbuf, bufferlen) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* replace_write_i2d */ |
| |
| static sf_count_t |
| replace_write_f2d (SF_PRIVATE *psf, const float *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| f2d_array (ptr + total, psf->u.dbuf, bufferlen) ; |
| |
| bd2d_write (psf->u.dbuf, bufferlen) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* replace_write_f2d */ |
| |
| static sf_count_t |
| replace_write_d (SF_PRIVATE *psf, const double *ptr, sf_count_t len) |
| { int bufferlen, writecount ; |
| sf_count_t total = 0 ; |
| |
| /* FIXME : This is probably nowhere near optimal. */ |
| if (psf->peak_info) |
| double64_peak_update (psf, ptr, len, 0) ; |
| |
| bufferlen = ARRAY_LEN (psf->u.dbuf) ; |
| |
| while (len > 0) |
| { if (len < bufferlen) |
| bufferlen = (int) len ; |
| |
| memcpy (psf->u.dbuf, ptr + total, bufferlen * sizeof (double)) ; |
| |
| bd2d_write (psf->u.dbuf, bufferlen) ; |
| |
| if (psf->data_endswap == SF_TRUE) |
| endswap_double_array (psf->u.dbuf, bufferlen) ; |
| |
| writecount = psf_fwrite (psf->u.dbuf, sizeof (double), bufferlen, psf) ; |
| total += writecount ; |
| if (writecount < bufferlen) |
| break ; |
| len -= writecount ; |
| } ; |
| |
| return total ; |
| } /* replace_write_d */ |
| |
| /*---------------------------------------------------------------------------------------------- |
| */ |
| |
| static void |
| d2bd_read (double *buffer, int count) |
| { while (--count >= 0) |
| { buffer [count] = DOUBLE64_READ ((unsigned char *) (buffer + count)) ; |
| } ; |
| } /* d2bd_read */ |
| |
| static void |
| bd2d_write (double *buffer, int count) |
| { while (--count >= 0) |
| { DOUBLE64_WRITE (buffer [count], (unsigned char*) (buffer + count)) ; |
| } ; |
| } /* bd2d_write */ |
| |