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