1e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent/*
2e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *
4e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  Use of this source code is governed by a BSD-style license
5e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  that can be found in the LICENSE file in the root of the source
6e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  tree. An additional intellectual property rights grant can be found
7e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  in the file PATENTS.  All contributing project authors may
8e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *  be found in the AUTHORS file in the root of the source tree.
9e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent */
10e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
11e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
12e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent/*
13e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * This file contains implementations of the divisions
14e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * WebRtcSpl_DivU32U16()
15e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * WebRtcSpl_DivW32W16()
16e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * WebRtcSpl_DivW32W16ResW16()
17e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * WebRtcSpl_DivResultInQ31()
18e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * WebRtcSpl_DivW32HiLow()
19e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *
20e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent * The description header can be found in signal_processing_library.h
21e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent *
22e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent */
23e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
24e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent#include "signal_processing_library.h"
25e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
26e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_UWord32 WebRtcSpl_DivU32U16(WebRtc_UWord32 num, WebRtc_UWord16 den)
27e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
28e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Guard against division with 0
29e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (den != 0)
30e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
31e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_UWord32)(num / den);
32e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
33e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
34e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_UWord32)0xFFFFFFFF;
35e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
36e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
37e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
38e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_Word32 WebRtcSpl_DivW32W16(WebRtc_Word32 num, WebRtc_Word16 den)
39e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
40e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Guard against division with 0
41e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (den != 0)
42e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
43e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_Word32)(num / den);
44e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
45e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
46e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_Word32)0x7FFFFFFF;
47e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
48e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
49e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
50e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_Word16 WebRtcSpl_DivW32W16ResW16(WebRtc_Word32 num, WebRtc_Word16 den)
51e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
52e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Guard against division with 0
53e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (den != 0)
54e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
55e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_Word16)(num / den);
56e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    } else
57e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
58e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return (WebRtc_Word16)0x7FFF;
59e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
60e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
61e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
62e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_Word32 WebRtcSpl_DivResultInQ31(WebRtc_Word32 num, WebRtc_Word32 den)
63e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
64e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 L_num = num;
65e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 L_den = den;
66e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 div = 0;
67e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int k = 31;
68e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    int change_sign = 0;
69e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
70e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (num == 0)
71e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        return 0;
72e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
73e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (num < 0)
74e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
75e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        change_sign++;
76e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        L_num = -num;
77e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
78e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (den < 0)
79e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
80e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        change_sign++;
81e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        L_den = -den;
82e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
83e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    while (k--)
84e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
85e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        div <<= 1;
86e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        L_num <<= 1;
87e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        if (L_num >= L_den)
88e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        {
89e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            L_num -= L_den;
90e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            div++;
91e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        }
92e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
93e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    if (change_sign == 1)
94e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    {
95e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent        div = -div;
96e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    }
97e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    return div;
98e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
99e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
100e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric LaurentWebRtc_Word32 WebRtcSpl_DivW32HiLow(WebRtc_Word32 num, WebRtc_Word16 den_hi,
101e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent                                    WebRtc_Word16 den_low)
102e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent{
103e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word16 approx, tmp_hi, tmp_low, num_hi, num_low;
104e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    WebRtc_Word32 tmpW32;
105e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
106e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    approx = (WebRtc_Word16)WebRtcSpl_DivW32W16((WebRtc_Word32)0x1FFFFFFF, den_hi);
107e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30)
108e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
109e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30)
110e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpW32 = (WEBRTC_SPL_MUL_16_16(den_hi, approx) << 1)
111e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            + ((WEBRTC_SPL_MUL_16_16(den_low, approx) >> 15) << 1);
112e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // tmpW32 = den * approx
113e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
114e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpW32 = (WebRtc_Word32)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
115e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
116e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Store tmpW32 in hi and low format
117e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
118e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32
119e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1);
120e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
121e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // tmpW32 = 1/den in Q29
122e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpW32 = ((WEBRTC_SPL_MUL_16_16(tmp_hi, approx) + (WEBRTC_SPL_MUL_16_16(tmp_low, approx)
123e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            >> 15)) << 1);
124e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
125e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // 1/den in hi and low format
126e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(tmpW32, 16);
127e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmp_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((tmpW32
128e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)tmp_hi, 16)), 1);
129e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
130e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Store num in hi and low format
131e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    num_hi = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32(num, 16);
132e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    num_low = (WebRtc_Word16)WEBRTC_SPL_RSHIFT_W32((num
133e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            - WEBRTC_SPL_LSHIFT_W32((WebRtc_Word32)num_hi, 16)), 1);
134e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
135e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // num * (1/den) by 32 bit multiplication (result in Q28)
136e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
137e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpW32 = (WEBRTC_SPL_MUL_16_16(num_hi, tmp_hi) + (WEBRTC_SPL_MUL_16_16(num_hi, tmp_low)
138e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent            >> 15) + (WEBRTC_SPL_MUL_16_16(num_low, tmp_hi) >> 15));
139e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
140e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    // Put result in Q31 (convert from Q28)
141e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3);
142e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent
143e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent    return tmpW32;
144e48d5845c8b35de2ab73ea055c18a61fa3a9f0beEric Laurent}
145