niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
| 11 | |
| 12 | // This header file includes the inline functions in |
| 13 | // the fix point signal processing library. |
| 14 | |
oprypin | 67fdb80 | 2017-03-09 06:25:06 -0800 | [diff] [blame] | 15 | #ifndef WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ |
| 16 | #define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 17 | |
Edward Lemur | c20978e | 2017-07-06 19:44:34 +0200 | [diff] [blame] | 18 | #include "webrtc/rtc_base/compile_assert_c.h" |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 19 | |
| 20 | extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64]; |
| 21 | |
| 22 | // Don't call this directly except in tests! |
| 23 | static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) { |
| 24 | // Normalize n by rounding up to the nearest number that is a sequence of 0 |
| 25 | // bits followed by a sequence of 1 bits. This number has the same number of |
| 26 | // leading zeros as the original n. There are exactly 33 such values. |
| 27 | n |= n >> 1; |
| 28 | n |= n >> 2; |
| 29 | n |= n >> 4; |
| 30 | n |= n >> 8; |
| 31 | n |= n >> 16; |
| 32 | |
| 33 | // Multiply the modified n with a constant selected (by exhaustive search) |
| 34 | // such that each of the 33 possible values of n give a product whose 6 most |
| 35 | // significant bits are unique. Then look up the answer in the table. |
| 36 | return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26]; |
| 37 | } |
| 38 | |
| 39 | // Don't call this directly except in tests! |
| 40 | static __inline int WebRtcSpl_CountLeadingZeros64_NotBuiltin(uint64_t n) { |
| 41 | const int leading_zeros = n >> 32 == 0 ? 32 : 0; |
| 42 | return leading_zeros + WebRtcSpl_CountLeadingZeros32_NotBuiltin( |
| 43 | (uint32_t)(n >> (32 - leading_zeros))); |
| 44 | } |
| 45 | |
| 46 | // Returns the number of leading zero bits in the argument. |
| 47 | static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) { |
| 48 | #ifdef __GNUC__ |
kjellander | e0ab0ad | 2017-04-10 23:21:43 -0700 | [diff] [blame] | 49 | RTC_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t)); |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 50 | return n == 0 ? 32 : __builtin_clz(n); |
| 51 | #else |
| 52 | return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n); |
| 53 | #endif |
| 54 | } |
| 55 | |
| 56 | // Returns the number of leading zero bits in the argument. |
| 57 | static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) { |
| 58 | #ifdef __GNUC__ |
kjellander | e0ab0ad | 2017-04-10 23:21:43 -0700 | [diff] [blame] | 59 | RTC_COMPILE_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); // NOLINT |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 60 | return n == 0 ? 64 : __builtin_clzll(n); |
| 61 | #else |
| 62 | return WebRtcSpl_CountLeadingZeros64_NotBuiltin(n); |
| 63 | #endif |
| 64 | } |
| 65 | |
kma@webrtc.org | 94771cb | 2012-08-28 04:09:50 +0000 | [diff] [blame] | 66 | #ifdef WEBRTC_ARCH_ARM_V7 |
pbos@webrtc.org | aa30bb7 | 2013-05-27 09:49:58 +0000 | [diff] [blame] | 67 | #include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h" |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 68 | #else |
| 69 | |
andrew@webrtc.org | 8bf755d | 2013-09-18 17:40:46 +0000 | [diff] [blame] | 70 | #if defined(MIPS32_LE) |
| 71 | #include "webrtc/common_audio/signal_processing/include/spl_inl_mips.h" |
| 72 | #endif |
| 73 | |
| 74 | #if !defined(MIPS_DSP_R1_LE) |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 75 | static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { |
| 76 | int16_t out16 = (int16_t) value32; |
kma@google.com | 961885a | 2011-09-26 16:35:25 +0000 | [diff] [blame] | 77 | |
| 78 | if (value32 > 32767) |
| 79 | out16 = 32767; |
| 80 | else if (value32 < -32768) |
| 81 | out16 = -32768; |
| 82 | |
| 83 | return out16; |
| 84 | } |
| 85 | |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 86 | static __inline int32_t WebRtcSpl_AddSatW32(int32_t a, int32_t b) { |
| 87 | // Do the addition in unsigned numbers, since signed overflow is undefined |
| 88 | // behavior. |
| 89 | const int32_t sum = (int32_t)((uint32_t)a + (uint32_t)b); |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 90 | |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 91 | // a + b can't overflow if a and b have different signs. If they have the |
| 92 | // same sign, a + b also has the same sign iff it didn't overflow. |
| 93 | if ((a < 0) == (b < 0) && (a < 0) != (sum < 0)) { |
| 94 | // The direction of the overflow is obvious from the sign of a + b. |
| 95 | return sum < 0 ? INT32_MAX : INT32_MIN; |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 96 | } |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 97 | return sum; |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 98 | } |
| 99 | |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 100 | static __inline int32_t WebRtcSpl_SubSatW32(int32_t a, int32_t b) { |
| 101 | // Do the subtraction in unsigned numbers, since signed overflow is undefined |
| 102 | // behavior. |
| 103 | const int32_t diff = (int32_t)((uint32_t)a - (uint32_t)b); |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 104 | |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 105 | // a - b can't overflow if a and b have the same sign. If they have different |
| 106 | // signs, a - b has the same sign as a iff it didn't overflow. |
| 107 | if ((a < 0) != (b < 0) && (a < 0) != (diff < 0)) { |
| 108 | // The direction of the overflow is obvious from the sign of a - b. |
| 109 | return diff < 0 ? INT32_MAX : INT32_MIN; |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 110 | } |
kwiberg | bca568b | 2016-05-23 04:07:00 -0700 | [diff] [blame] | 111 | return diff; |
bjornv@webrtc.org | 1de0cc4 | 2014-08-26 09:36:25 +0000 | [diff] [blame] | 112 | } |
| 113 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 114 | static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { |
| 115 | return WebRtcSpl_SatW32ToW16((int32_t) a + (int32_t) b); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 116 | } |
| 117 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 118 | static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { |
| 119 | return WebRtcSpl_SatW32ToW16((int32_t) var1 - (int32_t) var2); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 120 | } |
andrew@webrtc.org | 8bf755d | 2013-09-18 17:40:46 +0000 | [diff] [blame] | 121 | #endif // #if !defined(MIPS_DSP_R1_LE) |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 122 | |
andrew@webrtc.org | 8bf755d | 2013-09-18 17:40:46 +0000 | [diff] [blame] | 123 | #if !defined(MIPS32_LE) |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 124 | static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 125 | return 32 - WebRtcSpl_CountLeadingZeros32(n); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 126 | } |
| 127 | |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 128 | // Return the number of steps a can be left-shifted without overflow, |
| 129 | // or 0 if a == 0. |
bjornv@webrtc.org | 3cbd6c2 | 2014-09-04 13:21:44 +0000 | [diff] [blame] | 130 | static __inline int16_t WebRtcSpl_NormW32(int32_t a) { |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 131 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 132 | } |
| 133 | |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 134 | // Return the number of steps a can be left-shifted without overflow, |
| 135 | // or 0 if a == 0. |
bjornv@webrtc.org | 3cbd6c2 | 2014-09-04 13:21:44 +0000 | [diff] [blame] | 136 | static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 137 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a); |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 138 | } |
| 139 | |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 140 | // Return the number of steps a can be left-shifted without overflow, |
| 141 | // or 0 if a == 0. |
bjornv@webrtc.org | 3cbd6c2 | 2014-09-04 13:21:44 +0000 | [diff] [blame] | 142 | static __inline int16_t WebRtcSpl_NormW16(int16_t a) { |
kwiberg | 729b21f | 2016-06-02 04:02:12 -0700 | [diff] [blame] | 143 | const int32_t a32 = a; |
| 144 | return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17; |
niklase@google.com | 470e71d | 2011-07-07 08:21:25 +0000 | [diff] [blame] | 145 | } |
| 146 | |
pbos@webrtc.org | b091307 | 2013-04-09 16:40:28 +0000 | [diff] [blame] | 147 | static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { |
kma@webrtc.org | a58224f | 2011-10-05 16:44:11 +0000 | [diff] [blame] | 148 | return (a * b + c); |
| 149 | } |
andrew@webrtc.org | 8bf755d | 2013-09-18 17:40:46 +0000 | [diff] [blame] | 150 | #endif // #if !defined(MIPS32_LE) |
kma@webrtc.org | a58224f | 2011-10-05 16:44:11 +0000 | [diff] [blame] | 151 | |
kma@webrtc.org | 94771cb | 2012-08-28 04:09:50 +0000 | [diff] [blame] | 152 | #endif // WEBRTC_ARCH_ARM_V7 |
kma@google.com | 0ada410 | 2011-09-09 16:23:50 +0000 | [diff] [blame] | 153 | |
oprypin | 67fdb80 | 2017-03-09 06:25:06 -0800 | [diff] [blame] | 154 | #endif // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ |