1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <math.h> 18 #include <audio_utils/sample.h> 19 20 #define SAMPLE_NEG_MAX 0xFFFF 21 #define SAMPLE_POS_MAX 0x7FFF 22 23 #define SIGN_MASK 0x8000 24 #define SIGN_BITS 1 25 26 #define EXPONENT_BITS 3 27 #define EXPONENT_MAX ((1 << EXPONENT_BITS) - 1) 28 #define EXCESS ((1 << EXPONENT_BITS) - 2) 29 30 #define MANTISSA_BITS 12 31 #define MANTISSA_MAX ((1 << MANTISSA_BITS) - 1) 32 #define HIDDEN_BIT (1 << MANTISSA_BITS) 33 #define ONE_FLOAT ((float) (1 << (MANTISSA_BITS + 1))) 34 35 36 #if SIGN_BITS + EXPONENT_BITS + MANTISSA_BITS != 16 37 #error SIGN_BITS, EXPONENT_BITS and MANTISSA_BITS must sum to 16 38 #endif 39 sample_from_float(float v)40sample_minifloat_t sample_from_float(float v) 41 { 42 if (isnan(v)) { 43 return 0; 44 } 45 sample_minifloat_t sign = 0; 46 if (v < 0.0f) { 47 sign = SIGN_MASK; 48 v = -v; 49 } 50 // This check could conceivably be tighter: v < constexpr float_from_sample(1). 51 // Probably only useful to be made more accurate if this is changed to 52 // manipulate the raw IEEE single precision float bit fields. 53 if (v <= 0.0f) { 54 // originally returned sign, but now seems better not to return negative 0 55 return 0; 56 } 57 if (v >= 2.0f) { 58 return SAMPLE_POS_MAX | sign; 59 } 60 int exp; 61 float r = frexpf(v, &exp); 62 if ((exp += EXCESS) > EXPONENT_MAX) { 63 return SAMPLE_POS_MAX | sign; 64 } 65 if (-exp >= MANTISSA_BITS) { 66 // originally returned sign, but now seems better not to return negative 0 67 return 0; 68 } 69 int mantissa = (int) (r * ONE_FLOAT); 70 sample_minifloat_t ret = exp > 0 ? (exp << MANTISSA_BITS) | (mantissa & ~HIDDEN_BIT) : 71 (mantissa >> (1 - exp)) & MANTISSA_MAX; 72 // ret != 0 73 return ret | sign; 74 } 75 float_from_sample(sample_minifloat_t a)76float float_from_sample(sample_minifloat_t a) 77 { 78 int mantissa = a & MANTISSA_MAX; 79 int exponent = (a >> MANTISSA_BITS) & EXPONENT_MAX; 80 float f = ldexpf((exponent > 0 ? HIDDEN_BIT | mantissa : mantissa << 1) / ONE_FLOAT, 81 exponent - EXCESS); 82 return a & SIGN_MASK ? -f : f; 83 } 84