summaryrefslogtreecommitdiff
path: root/webrtc/common_audio/signal_processing/division_operations.c
blob: c6195e799954463ad5b439e789c2f3bbf9c638eb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
/*
 *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */


/*
 * This file contains implementations of the divisions
 * WebRtcSpl_DivU32U16()
 * WebRtcSpl_DivW32W16()
 * WebRtcSpl_DivW32W16ResW16()
 * WebRtcSpl_DivResultInQ31()
 * WebRtcSpl_DivW32HiLow()
 *
 * The description header can be found in signal_processing_library.h
 *
 */

#include "common_audio/signal_processing/include/signal_processing_library.h"
#include "rtc_base/sanitizer.h"

uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den)
{
    // Guard against division with 0
    if (den != 0)
    {
        return (uint32_t)(num / den);
    } else
    {
        return (uint32_t)0xFFFFFFFF;
    }
}

int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den)
{
    // Guard against division with 0
    if (den != 0)
    {
        return (int32_t)(num / den);
    } else
    {
        return (int32_t)0x7FFFFFFF;
    }
}

int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den)
{
    // Guard against division with 0
    if (den != 0)
    {
        return (int16_t)(num / den);
    } else
    {
        return (int16_t)0x7FFF;
    }
}

int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den)
{
    int32_t L_num = num;
    int32_t L_den = den;
    int32_t div = 0;
    int k = 31;
    int change_sign = 0;

    if (num == 0)
        return 0;

    if (num < 0)
    {
        change_sign++;
        L_num = -num;
    }
    if (den < 0)
    {
        change_sign++;
        L_den = -den;
    }
    while (k--)
    {
        div <<= 1;
        L_num <<= 1;
        if (L_num >= L_den)
        {
            L_num -= L_den;
            div++;
        }
    }
    if (change_sign == 1)
    {
        div = -div;
    }
    return div;
}

int32_t RTC_NO_SANITIZE("signed-integer-overflow")  // bugs.webrtc.org/5486
WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low)
{
    int16_t approx, tmp_hi, tmp_low, num_hi, num_low;
    int32_t tmpW32;

    approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi);
    // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)

    // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
    tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1);
    // tmpW32 = den * approx

    tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
    // UBSan: 2147483647 - -2 cannot be represented in type 'int'

    // Store tmpW32 in hi and low format
    tmp_hi = (int16_t)(tmpW32 >> 16);
    tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);

    // tmpW32 = 1/den in Q29
    tmpW32 = (tmp_hi * approx + (tmp_low * approx >> 15)) << 1;

    // 1/den in hi and low format
    tmp_hi = (int16_t)(tmpW32 >> 16);
    tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1);

    // Store num in hi and low format
    num_hi = (int16_t)(num >> 16);
    num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1);

    // num * (1/den) by 32 bit multiplication (result in Q28)

    tmpW32 = num_hi * tmp_hi + (num_hi * tmp_low >> 15) +
        (num_low * tmp_hi >> 15);

    // Put result in Q31 (convert from Q28)
    tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);

    return tmpW32;
}