/*- * vim:sw=2 ts=8:noet nosta:fdm=marker * * * Copyright (c) 2014 Ariff Abdullah * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include typedef int32_t intpcm_t; #define INTPCM_T(v) ((intpcm_t)(v)) #define PCM_S32_MAX 0x7fffffff #define PCM_S32_MIN (-0x7fffffff - 1) /*** *** BEWARE OF STRICT ALIASING *** BEWARE OF STRICT ALIASING ***/ #undef SND_IEEE754_OE #define SND_IEEE754_OE static __inline intpcm_t intpcm_read_ieee754_32ne(uint8_t *src) { uint32_t v; int32_t s, e, m; v = *((uint32_t *)src); e = (v >> 23) & 0xff; /* NaN, +/- Inf or too small */ if (e == 0xff || e < 96) return (INTPCM_T(0)); s = ((v & 0x80000000U) != 0) ? 1 : 0; if (e > 126) return (INTPCM_T((s == 0) ? PCM_S32_MAX : PCM_S32_MIN)); m = 0x800000 | (v & 0x7fffff); e += 8 - 127; if (e < 0) m >>= -e; else m <<= e; return (INTPCM_T((s == 0) ? m : -m)); } static __inline void intpcm_write_ieee754_32ne(uint8_t *dst, intpcm_t v) { uint32_t r; int32_t e; if (v == 0) r = 0; else if (v == PCM_S32_MAX) r = 0x3f800000; else if (v == PCM_S32_MIN) r = 0x80000000U | 0x3f800000; else { r = 0; if (v < 0) { r |= 0x80000000U; v = -v; } e = 127 - 8; while ((v & 0x7f000000) != 0) { v >>= 1; e++; } while ((v & 0x7f800000) == 0) { v <<= 1; e--; } r |= (e & 0xff) << 23; r |= v & 0x7fffff; } *((uint32_t *)dst) = r; } #define intpcm_read_float intpcm_read_ieee754_32ne #define intpcm_write_float intpcm_write_ieee754_32ne #ifdef SND_IEEE754_OE static __inline intpcm_t intpcm_read_ieee754_32oe(uint8_t *src) { #if 1 uint32_t v; v = bswap32(*((uint32_t *)src)); return (intpcm_read_ieee754_32ne((uint8_t *)&v)); #else uint8_t b[sizeof(uint32_t)]; *((uint32_t *)b) = bswap32(*((uint32_t *)src)); return (intpcm_read_ieee754_32ne(b)); #endif } static __inline void intpcm_write_ieee754_32oe(uint8_t *dst, intpcm_t v) { intpcm_write_ieee754_32ne(dst, v); *((uint32_t *)dst) = bswap32(*((uint32_t *)dst)); } #if BYTE_ORDER == LITTLE_ENDIAN #define intpcm_read_ieee754_32le intpcm_read_ieee754_32ne #define intpcm_read_ieee754_32be intpcm_read_ieee754_32oe #define intpcm_write_ieee754_32le intpcm_write_ieee754_32ne #define intpcm_write_ieee754_32be intpcm_write_ieee754_32oe #else /* !LITTLE_ENDIAN */ #define intpcm_read_ieee754_32le intpcm_read_ieee754_32oe #define intpcm_read_ieee754_32be intpcm_read_ieee754_32ne #define intpcm_write_ieee754_32le intpcm_write_ieee754_32oe #define intpcm_write_ieee754_32be intpcm_write_ieee754_32ne #endif /* LITTLE_ENDIAN */ #endif /* SND_IEEE754_OE */ int main(int argc, char **argv) { uint32_t v, w; uint8_t b[sizeof(uint32_t)]; int32_t s; float f, g; int i, j; for (j = 1; j < argc ; j++) { printf("***** FLOAT: [ %s ]\n", argv[j]); if (strncmp(argv[j], "oe:", 3) == 0) { f = strtof(argv[j] + 3, NULL); memcpy(b, &f, sizeof(b)); *((uint32_t *)b) = bswap32(*((uint32_t *)b)); s = intpcm_read_ieee754_32oe(b); intpcm_write_ieee754_32oe(b, s); *((uint32_t *)b) = bswap32(*((uint32_t *)b)); memcpy(&g, b, sizeof(g)); printf(" -> %.16f\n <- %.16f\n err: %.16f\n", (double)f, (double)g, (double)f - g); } else f = strtof(argv[j], NULL); memcpy(b, &f, sizeof(b)); v = *((uint32_t *)b); s = intpcm_read_float(b); intpcm_write_float(b, s); w = *((uint32_t *)b); memcpy(&g, b, sizeof(g)); printf(" %.16f / 0x%08x -> %d\n 0x%08x / %.16f " "(err: %.16f)\n\t%u " "[ %u -> %d ] [ %u -> %u ]\n", (double)f, v, s, w, (double)g, (double)f - g, v >> 31, (v >> 23) & 0xff, ((int)(v >> 23) & 0xff) - 127, v & ((1 << 23) - 1), (1 << 23) | (v & ((1 << 23) - 1))); printf("\t%u ", v >> 31); for (i = 30; i >= 23; i--) printf("%u", (v >> i) & 0x1); printf(" *"); for (i = 23; i >= 0; i--) printf("%u", ((v | (1 << 23)) >> i) & 0x1); printf("\n"); } return (0); }