📄 float32.c
字号:
/*** Copyright (C) 1999-2004 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 <stdio.h>#include <stdlib.h>#include <string.h>#include "sndfile.h"#include "config.h"#include "sfendian.h"#include "common.h"#include "float_cast.h"#if CPU_IS_LITTLE_ENDIAN #define FLOAT32_READ float32_le_read #define FLOAT32_WRITE float32_le_write#elif CPU_IS_BIG_ENDIAN #define FLOAT32_READ float32_be_read #define FLOAT32_WRITE float32_be_write#endif/*--------------------------------------------------------------------------------------------** Processor floating point capabilities. float32_get_capability () returns one of the** latter four values.*/enum{ FLOAT_UNKNOWN = 0x00, FLOAT_CAN_RW_LE = 0x12, FLOAT_CAN_RW_BE = 0x23, FLOAT_BROKEN_LE = 0x34, FLOAT_BROKEN_BE = 0x45} ;/*--------------------------------------------------------------------------------------------** Prototypes for private functions.*/static sf_count_t host_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;static sf_count_t host_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;static sf_count_t host_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;static sf_count_t host_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;static sf_count_t host_write_s2f (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;static sf_count_t host_write_i2f (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;static sf_count_t host_write_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;static sf_count_t host_write_d2f (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;static void float32_peak_update (SF_PRIVATE *psf, float *buffer, int count, int indx) ;static sf_count_t replace_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;static sf_count_t replace_read_f2i (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;static sf_count_t replace_read_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;static sf_count_t replace_read_f2d (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;static sf_count_t replace_write_s2f (SF_PRIVATE *psf, short *ptr, sf_count_t len) ;static sf_count_t replace_write_i2f (SF_PRIVATE *psf, int *ptr, sf_count_t len) ;static sf_count_t replace_write_f (SF_PRIVATE *psf, float *ptr, sf_count_t len) ;static sf_count_t replace_write_d2f (SF_PRIVATE *psf, double *ptr, sf_count_t len) ;static void bf2f_array (float *buffer, int count) ;static void f2bf_array (float *buffer, int count) ;static int float32_get_capability (SF_PRIVATE *psf) ;/*--------------------------------------------------------------------------------------------** Exported functions.*/intfloat32_init (SF_PRIVATE *psf){ static int float_caps ; float_caps = float32_get_capability (psf) ; psf->blockwidth = sizeof (float) * psf->sf.channels ; if (psf->mode == SFM_READ || psf->mode == SFM_RDWR) { switch (psf->endian + float_caps) { case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = host_read_f2s ; psf->read_int = host_read_f2i ; psf->read_float = host_read_f ; psf->read_double = host_read_f2d ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->read_short = replace_read_f2s ; psf->read_int = replace_read_f2i ; psf->read_float = replace_read_f ; psf->read_double = replace_read_f2d ; break ; default : break ; } ; } ; if (psf->mode == SFM_WRITE || psf->mode == SFM_RDWR) { switch (psf->endian + float_caps) { case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_CAN_RW_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_CAN_RW_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = host_write_s2f ; psf->write_int = host_write_i2f ; psf->write_float = host_write_f ; psf->write_double = host_write_d2f ; break ; /* When the CPU is not IEEE compatible. */ case (SF_ENDIAN_BIG + FLOAT_BROKEN_LE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_LE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_BIG + FLOAT_BROKEN_BE) : psf->float_endswap = SF_FALSE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; break ; case (SF_ENDIAN_LITTLE + FLOAT_BROKEN_BE) : psf->float_endswap = SF_TRUE ; psf->write_short = replace_write_s2f ; psf->write_int = replace_write_i2f ; psf->write_float = replace_write_f ; psf->write_double = replace_write_d2f ; 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 ;} /* float32_init */floatfloat32_be_read (unsigned char *cptr){ int exponent, mantissa, negative ; float fvalue ; negative = cptr [0] & 0x80 ; exponent = ((cptr [0] & 0x7F) << 1) | ((cptr [1] & 0x80) ? 1 : 0) ; mantissa = ((cptr [1] & 0x7F) << 16) | (cptr [2] << 8) | (cptr [3]) ; if (! (exponent || mantissa)) return 0.0 ; mantissa |= 0x800000 ; exponent = exponent ? exponent - 127 : 0 ; fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; if (negative) fvalue *= -1 ; if (exponent > 0) fvalue *= (1 << exponent) ; else if (exponent < 0) fvalue /= (1 << abs (exponent)) ; return fvalue ;} /* float32_be_read */floatfloat32_le_read (unsigned char *cptr){ int exponent, mantissa, negative ; float fvalue ; negative = cptr [3] & 0x80 ; exponent = ((cptr [3] & 0x7F) << 1) | ((cptr [2] & 0x80) ? 1 : 0) ; mantissa = ((cptr [2] & 0x7F) << 16) | (cptr [1] << 8) | (cptr [0]) ; if (! (exponent || mantissa)) return 0.0 ; mantissa |= 0x800000 ; exponent = exponent ? exponent - 127 : 0 ; fvalue = mantissa ? ((float) mantissa) / ((float) 0x800000) : 0.0 ; if (negative) fvalue *= -1 ; if (exponent > 0) fvalue *= (1 << exponent) ; else if (exponent < 0) fvalue /= (1 << abs (exponent)) ; return fvalue ;} /* float32_le_read */voidfloat32_le_write (float in, unsigned char *out){ int exponent, mantissa, negative = 0 ; memset (out, 0, sizeof (int)) ; if (in == 0.0) return ; if (in < 0.0) { in *= -1.0 ; negative = 1 ; } ; in = frexp (in, &exponent) ; exponent += 126 ; in *= (float) 0x1000000 ; mantissa = (((int) in) & 0x7FFFFF) ; if (negative) out [3] |= 0x80 ; if (exponent & 0x01) out [2] |= 0x80 ; out [0] = mantissa & 0xFF ; out [1] = (mantissa >> 8) & 0xFF ; out [2] |= (mantissa >> 16) & 0x7F ; out [3] |= (exponent >> 1) & 0x7F ; return ;} /* float32_le_write */voidfloat32_be_write (float in, unsigned char *out){ int exponent, mantissa, negative = 0 ; memset (out, 0, sizeof (int)) ; if (in == 0.0) return ; if (in < 0.0) { in *= -1.0 ; negative = 1 ; } ; in = frexp (in, &exponent) ; exponent += 126 ; in *= (float) 0x1000000 ; mantissa = (((int) in) & 0x7FFFFF) ; if (negative) out [0] |= 0x80 ; if (exponent & 0x01) out [1] |= 0x80 ; out [3] = mantissa & 0xFF ; out [2] = (mantissa >> 8) & 0xFF ; out [1] |= (mantissa >> 16) & 0x7F ; out [0] |= (exponent >> 1) & 0x7F ; return ;} /* float32_be_write *//*==============================================================================================** Private functions.*/static voidfloat32_peak_update (SF_PRIVATE *psf, float *buffer, int count, int 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->pchunk->peaks [chan].value) { psf->pchunk->peaks [chan].value = fmaxval ; psf->pchunk->peaks [chan].position = psf->write_current + indx + (position / psf->sf.channels) ; } ; } ; return ;} /* float32_peak_update */static intfloat32_get_capability (SF_PRIVATE *psf){ union { float f ; int i ; unsigned char c [4] ; } data ; data.f = (float) 1.23456789 ; /* Some abitrary value. */ if (! psf->ieee_replace) { /* If this test is true ints and floats are compatible and little endian. */ if (data.c [0] == 0x52 && data.c [1] == 0x06 && data.c [2] == 0x9e && data.c [3] == 0x3f) return FLOAT_CAN_RW_LE ; /* If this test is true ints and floats are compatible and big endian. */ if (data.c [3] == 0x52 && data.c [2] == 0x06 && data.c [1] == 0x9e && data.c [0] == 0x3f) return FLOAT_CAN_RW_BE ; } ; /* Floats are broken. Don't expect reading or writing to be fast. */ psf_log_printf (psf, "Using IEEE replacement code for float.\n") ; return (CPU_IS_LITTLE_ENDIAN) ? FLOAT_BROKEN_LE : FLOAT_BROKEN_BE ;} /* float32_get_capability *//*=======================================================================================*/static inline voidf2s_array (float *src, int count, short *dest, float scale){ while (--count >= 0) { dest [count] = lrintf (scale * src [count]) ; } ;} /* f2s_array */static inline voidf2i_array (float *src, int count, int *dest, float scale){ while (--count >= 0) { dest [count] = lrintf (scale * src [count]) ; } ;} /* f2i_array */static inline voidf2d_array (float *src, int count, double *dest){ while (--count >= 0) { dest [count] = src [count] ; } ;} /* f2d_array */static inline voids2f_array (short *src, float *dest, int count){ while (--count >= 0) { dest [count] = src [count] ; } ;} /* s2f_array */static inline voidi2f_array (int *src, float *dest, int count){ while (--count >= 0) { dest [count] = src [count] ; } ;} /* i2f_array */static inline voidd2f_array (double *src, float *dest, int count){ while (--count >= 0) { dest [count] = src [count] ; } ;} /* d2f_array *//*----------------------------------------------------------------------------------------------*/static sf_count_thost_read_f2s (SF_PRIVATE *psf, short *ptr, sf_count_t len){ int bufferlen, readcount ; sf_count_t total = 0 ; float scale ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -