1470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
2470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
4470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  Use of this source code is governed by a BSD-style license
5470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  that can be found in the LICENSE file in the root of the source
6470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  tree. An additional intellectual property rights grant can be found
7470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  in the file PATENTS.  All contributing project authors may
8470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *  be found in the AUTHORS file in the root of the source tree.
9470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
10470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
11470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/*
12470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * arith_routinshist.c
13470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
14470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * This C file contains arithmetic encoding and decoding.
15470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
16470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
17470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
18470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com#include "arith_routins.h"
19470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
20470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
21470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/****************************************************************************
22470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * WebRtcIsacfix_EncHistMulti(...)
23470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
24470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Encode the histogram interval
25470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
26470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Input:
27470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - streamData        : in-/output struct containing bitstream
28470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - data              : data vector
29470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - cdf               : array of cdf arrays
30470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - lenData           : data vector length
31470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
32470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Return value             : 0 if ok
33470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *                            <0 if error detected
34470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
35470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.comint WebRtcIsacfix_EncHistMulti(Bitstr_enc *streamData,
360946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                               const int16_t *data,
370946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                               const uint16_t **cdf,
380946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                               const int16_t lenData)
39470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
400946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t W_lower;
410946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t W_upper;
420946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t W_upper_LSB;
430946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t W_upper_MSB;
440946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t *streamPtr;
450946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t negCarry;
460946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t *maxStreamPtr;
470946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint16_t *streamPtrCarry;
480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t cdfLo;
490946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t cdfHi;
50470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int k;
51470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
52470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
53470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* point to beginning of stream buffer
54470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com   * and set maximum streamPtr value */
55470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamPtr = streamData->stream + streamData->stream_index;
56470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  maxStreamPtr = streamData->stream + STREAM_MAXW16_60MS - 1;
57470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
58470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  W_upper = streamData->W_upper;
59470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
60470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = lenData; k > 0; k--)
61470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
62470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* fetch cdf_lower and cdf_upper from cdf tables */
630946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    cdfLo = (uint32_t) *(*cdf + (uint32_t)*data);
640946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org    cdfHi = (uint32_t) *(*cdf++ + (uint32_t)*data++ + 1);
65470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
66470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* update interval */
67470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper_LSB = W_upper & 0x0000FFFF;
68a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    W_upper_MSB = W_upper >> 16;
69470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_lower = WEBRTC_SPL_UMUL(W_upper_MSB, cdfLo);
70a3b5673879284f16a2f9f56bc14429eec4f20a0cbjornv@webrtc.org    W_lower += ((W_upper_LSB * cdfLo) >> 16);
71470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper = WEBRTC_SPL_UMUL(W_upper_MSB, cdfHi);
72a3b5673879284f16a2f9f56bc14429eec4f20a0cbjornv@webrtc.org    W_upper += ((W_upper_LSB * cdfHi) >> 16);
73470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
74470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* shift interval such that it begins at zero */
75470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper -= ++W_lower;
76470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
77470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* add integer to bitstream */
78470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamData->streamval += W_lower;
79470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
80470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* handle carry */
81470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (streamData->streamval < W_lower)
82470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
83470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* propagate carry */
84470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      streamPtrCarry = streamPtr;
85470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (streamData->full == 0) {
86470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        negCarry = *streamPtrCarry;
87470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        negCarry += 0x0100;
88470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        *streamPtrCarry = negCarry;
89470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        while (!(negCarry))
90470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        {
91470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          negCarry = *--streamPtrCarry;
92470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          negCarry++;
93470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          *streamPtrCarry = negCarry;
94470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
95470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
96470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        while ( !(++(*--streamPtrCarry)) );
97470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
98470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
99470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
100470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* renormalize interval, store most significant byte of streamval and update streamval
101470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com     * W_upper < 2^24 */
102470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while ( !(W_upper & 0xFF000000) )
103470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
104d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      W_upper <<= 8;
105470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (streamData->full == 0) {
106a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org        *streamPtr++ += (uint16_t)(streamData->streamval >> 24);
107470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 1;
108470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
109a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org        *streamPtr = (uint16_t)((streamData->streamval >> 24) << 8);
110470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 0;
111470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
112470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
113470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if( streamPtr > maxStreamPtr ) {
114470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        return -ISAC_DISALLOWED_BITSTREAM_LENGTH;
115470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
116d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      streamData->streamval <<= 8;
117470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
118470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
119470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
120470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* calculate new stream_index */
121470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->stream_index = streamPtr - streamData->stream;
122470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->W_upper = W_upper;
123470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
124470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  return 0;
125470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
126470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
127470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
128470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/****************************************************************************
129470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * WebRtcIsacfix_DecHistBisectMulti(...)
130470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
131470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Function to decode more symbols from the arithmetic bytestream, using
132470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * method of bisection cdf tables should be of size 2^k-1 (which corresponds
133470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * to an alphabet size of 2^k-2)
134470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
135470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Input:
136470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - streamData        : in-/output struct containing bitstream
137470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - cdf               : array of cdf arrays
138470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - cdfSize           : array of cdf table sizes+1 (power of two: 2^k)
139470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - lenData           : data vector length
140470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
141470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Output:
142470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - data              : data vector
143470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
144470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Return value             : number of bytes in the stream
145470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *                            <0 if error detected
146470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
1470946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgint16_t WebRtcIsacfix_DecHistBisectMulti(int16_t *data,
1480946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                         Bitstr_dec *streamData,
1490946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                         const uint16_t **cdf,
1500946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                         const uint16_t *cdfSize,
1510946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                         const int16_t lenData)
152470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
1530946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_lower = 0;
1540946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper;
1550946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_tmp;
1560946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper_LSB;
1570946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper_MSB;
1580946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    streamval;
1590946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  const uint16_t *streamPtr;
1600946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  const uint16_t *cdfPtr;
1610946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  int16_t     sizeTmp;
162470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int             k;
163470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
164470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
165470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamPtr = streamData->stream + streamData->stream_index;
166470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  W_upper = streamData->W_upper;
167470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
168470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Error check: should not be possible in normal operation */
169470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (W_upper == 0) {
170470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -2;
171470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
172470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
173470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* first time decoder is called for this stream */
174470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (streamData->stream_index == 0)
175470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
176470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* read first word from bytestream */
177d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker    streamval = (uint32_t)*streamPtr++ << 16;
178470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval |= *streamPtr++;
179470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
180470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval = streamData->streamval;
181470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
182470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
183470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = lenData; k > 0; k--)
184470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
185470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
186470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper_LSB = W_upper & 0x0000FFFF;
187a296725d0eea443b6cb181262069433866e2849fbjornv@webrtc.org    W_upper_MSB = W_upper >> 16;
188470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
189470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* start halfway the cdf range */
190f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org    sizeTmp = *cdfSize++ / 2;
191470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdfPtr = *cdf + (sizeTmp - 1);
192470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
193470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* method of bisection */
194470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    for ( ;; )
195470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
196470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
1971e3ef4b999ada52fc4e421d1d06b73068e855413bjornv@webrtc.org      W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
198f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org      sizeTmp /= 2;
199470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (sizeTmp == 0) {
200470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        break;
201470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
202470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
203470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (streamval > W_tmp)
204470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
205470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_lower = W_tmp;
206470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        cdfPtr += sizeTmp;
207470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
208470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_upper = W_tmp;
209470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        cdfPtr -= sizeTmp;
210470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
211470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
212470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (streamval > W_tmp)
213470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
214470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      W_lower = W_tmp;
215470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *data++ = cdfPtr - *cdf++;
216470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else {
217470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      W_upper = W_tmp;
218470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *data++ = cdfPtr - *cdf++ - 1;
219470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
220470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
221470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* shift interval to start at zero */
222470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper -= ++W_lower;
223470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
224470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* add integer to bitstream */
225470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval -= W_lower;
226470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
227470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* renormalize interval and update streamval */
228470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* W_upper < 2^24 */
229470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while ( !(W_upper & 0xFF000000) )
230470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
231470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* read next byte from stream */
232470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (streamData->full == 0) {
233d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker        streamval = (streamval << 8) | (*streamPtr++ & 0x00FF);
234470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 1;
235470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
236f71785cd3b282ad7d584d746ba5b19833a11692bbjornv@webrtc.org        streamval = (streamval << 8) | (*streamPtr >> 8);
237470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 0;
238470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
239d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      W_upper <<= 8;
240470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
241470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
242470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
243470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* Error check: should not be possible in normal operation */
244470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (W_upper == 0) {
245470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      return -2;
246470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
247470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
248470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
249470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
250470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->stream_index = streamPtr - streamData->stream;
251470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->W_upper = W_upper;
252470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->streamval = streamval;
253470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
254470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if ( W_upper > 0x01FFFFFF ) {
255470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (streamData->stream_index*2 - 3 + !streamData->full);
256470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
257470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (streamData->stream_index*2 - 2 + !streamData->full);
258470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
259470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
260470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
261470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
262470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com/****************************************************************************
263470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * WebRtcIsacfix_DecHistOneStepMulti(...)
264470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
265470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Function to decode more symbols from the arithmetic bytestream, taking
266470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * single step up or down at a time.
267470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * cdf tables can be of arbitrary size, but large tables may take a lot of
268470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * iterations.
269470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
270470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Input:
271470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - streamData        : in-/output struct containing bitstream
272470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - cdf               : array of cdf arrays
273470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - initIndex         : vector of initial cdf table search entries
274470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - lenData           : data vector length
275470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
276470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Output:
277470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *      - data              : data vector
278470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *
279470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com * Return value             : number of bytes in original stream
280470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com *                            <0 if error detected
281470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com */
2820946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.orgint16_t WebRtcIsacfix_DecHistOneStepMulti(int16_t *data,
2830946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                          Bitstr_dec *streamData,
2840946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                          const uint16_t **cdf,
2850946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                          const uint16_t *initIndex,
2860946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org                                          const int16_t lenData)
287470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com{
2880946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_lower;
2890946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper;
2900946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_tmp;
2910946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper_LSB;
2920946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    W_upper_MSB;
2930946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  uint32_t    streamval;
2940946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  const uint16_t *streamPtr;
2950946a56023d821e0deca04029bb016ae1f23aa82pbos@webrtc.org  const uint16_t *cdfPtr;
296470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  int             k;
297470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
298470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
299470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamPtr = streamData->stream + streamData->stream_index;
300470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  W_upper = streamData->W_upper;
301470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Error check: Should not be possible in normal operation */
302470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (W_upper == 0) {
303470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return -2;
304470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
305470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
306470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* Check if it is the first time decoder is called for this stream */
307470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if (streamData->stream_index == 0)
308470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
309470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* read first word from bytestream */
3107c15510f389b00fea03e8512cf1a09d0a344b8e9bjornv@webrtc.org    streamval = (uint32_t)(*streamPtr++) << 16;
311470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval |= *streamPtr++;
312470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
313470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval = streamData->streamval;
314470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
315470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
316470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  for (k = lenData; k > 0; k--)
317470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  {
318470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* find the integer *data for which streamval lies in [W_lower+1, W_upper] */
319470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper_LSB = W_upper & 0x0000FFFF;
320470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper_MSB = WEBRTC_SPL_RSHIFT_U32(W_upper, 16);
321470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
322470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* start at the specified table entry */
323470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    cdfPtr = *cdf + (*initIndex++);
324470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
3251e3ef4b999ada52fc4e421d1d06b73068e855413bjornv@webrtc.org    W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
326470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
327470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    if (streamval > W_tmp)
328470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
329470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for ( ;; )
330470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
331470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_lower = W_tmp;
332470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
333470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* range check */
334470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (cdfPtr[0] == 65535) {
335470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          return -3;
336470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
337470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
338470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *++cdfPtr);
3391e3ef4b999ada52fc4e421d1d06b73068e855413bjornv@webrtc.org        W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
340470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
341470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (streamval <= W_tmp) {
342470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          break;
343470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
344470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
345470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      W_upper = W_tmp;
346470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *data++ = cdfPtr - *cdf++ - 1;
347470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    } else {
348470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      for ( ;; )
349470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      {
350470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_upper = W_tmp;
351470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        --cdfPtr;
352470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
353470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        /* range check */
354470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (cdfPtr < *cdf) {
355470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          return -3;
356470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
357470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
358470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        W_tmp = WEBRTC_SPL_UMUL_32_16(W_upper_MSB, *cdfPtr);
3591e3ef4b999ada52fc4e421d1d06b73068e855413bjornv@webrtc.org        W_tmp += (W_upper_LSB * (*cdfPtr)) >> 16;
360470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
361470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        if (streamval > W_tmp) {
362470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com          break;
363470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        }
364470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
365470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      W_lower = W_tmp;
366470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      *data++ = cdfPtr - *cdf++;
367470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
368470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
369470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* shift interval to start at zero */
370470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    W_upper -= ++W_lower;
371470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
372470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* add integer to bitstream */
373470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    streamval -= W_lower;
374470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
375470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* renormalize interval and update streamval */
376470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    /* W_upper < 2^24 */
377470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    while ( !(W_upper & 0xFF000000) )
378470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    {
379470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      /* read next byte from stream */
380470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      if (streamData->full == 0) {
381d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker        streamval = (streamval << 8) | (*streamPtr++ & 0x00FF);
382470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 1;
383470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      } else {
384d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker        streamval = (streamval << 8) | (*streamPtr >> 8);
385470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com        streamData->full = 0;
386470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com      }
387d4e75016a3836c3aab992afff6bfd8d5e3862aacBjorn Volcker      W_upper <<= 8;
388470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    }
389470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
390470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
391470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->stream_index = streamPtr - streamData->stream;
392470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->W_upper = W_upper;
393470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  streamData->streamval = streamval;
394470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com
395470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  /* find number of bytes in original stream (determined by current interval width) */
396470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  if ( W_upper > 0x01FFFFFF ) {
397470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (streamData->stream_index*2 - 3 + !streamData->full);
398470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  } else {
399470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com    return (streamData->stream_index*2 - 2 + !streamData->full);
400470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com  }
401470e71d3649f6cac4688e83819640b012b5d38bbniklase@google.com}
402