📄 cook_fixpoint.h
字号:
/*
* COOK compatible decoder, fixed point implementation.
* Copyright (c) 2007 Ian Braithwaite
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
/**
* @file cook_fixpoint.h
*
* Cook AKA RealAudio G2 fixed point functions.
*
* Fixed point values are represented as 32 bit signed integers,
* which can be added and subtracted directly in C (without checks for
* overflow/saturation.
*
* Three multiplication routines are provided:
* 1) Multiplication by powers of two (2^-31 .. 2^31), implemented
* with C's bit shift operations.
* 2) Multiplication by 16 bit fractions (0 <= x < 1), implemented
* in C using two 16x16->32 bit integer multiplications.
* 3) A combination of the two above.
*/
/**
* Fixed point shift right with rounding.
*
* @param x fix point value
* @param i shift, 1..31
*/
static inline FIXP fixp_shr(FIXP x, int i)
{
return (x + (1 << (i-1))) >> i;
}
/**
* Fixed point multiply by power of two.
*
* @param x fix point value
* @param i integer power-of-two, -31..+31
*/
static inline FIXP fixp_pow2(FIXP x, int i)
{
if (i < 0)
return fixp_shr(x, -i);
else
return x << i; /* no check for overflow */
}
/**
* Combined fixed point multiply by fraction and power of two.
*
* @param a fix point value
* @param b fix point fraction, 0 <= b < 1
* @param i integer power-of-two, -31..+15
*/
static inline FIXP fixp_mult_pow2(FIXP a, FIXPU b, int i)
{
#define COOK_MUL_16_32
#ifdef COOK_MUL_16_32
int32_t hb = (a >> 16) * b;
uint32_t lb = (a & 0xffffUL) * b;
if (i < 0)
return (hb + (int32_t)(lb >> 16) + (1 << (-1-i))) >> -i;
else
/* no check for overflow */
return (hb << i) + (int32_t)((lb + (1 << (15-i))) >> (16-i));
#else
#ifdef COOK_MUL_32_64
int32_t bs = b;
int64_t ab = (int64_t) a * bs;
#else
int64_t ab = (int64_t) a * b;
#endif
return (ab + (1 << (15-i))) >> (16-i); /* no check for overflow */
#endif
}
/**
* Fixed point multiply by fraction.
*
* @param a fix point value
* @param b fix point fraction, 0 <= b < 1
*/
static inline FIXP fixp_mult(FIXP a, FIXPU b)
{
return fixp_mult_pow2(a, b, 0);
}
/**
* Initialise fixed point implementation.
* Fill in the sine/cosine table.
*
* @param q pointer to the COOKContext
*/
static inline int init_cook_math(COOKContext *q)
{
FIXPU *const sincos_lookup = q->math.sincos_lookup;
FIXP s = 0, c = 0x80000000; /* 0.0, -1.0 */
uint16_t a = 0xc910; /* 2^14 pi */
int i = 0;
sincos_lookup[i++] = 0x0000;
sincos_lookup[i++] = 0xffff;
while (i < 2050) {
FIXP s2 = s + fixp_mult_pow2(c - fixp_mult_pow2(s, a, -11), a, -10);
FIXP c2 = c - fixp_mult_pow2(s + fixp_mult_pow2(c, a, -11), a, -10);
s = s2;
c = c2;
sincos_lookup[i++] = -fixp_shr(s, 15);
sincos_lookup[i++] = FFMIN(-fixp_shr(c, 15), 0xffff);
}
return 0;
}
/**
* Free resources used by floating point implementation.
* Nothing to do for fixed point.
*
* @param q pointer to the COOKContext
*/
static inline void free_cook_math(COOKContext *q)
{
return;
}
/**
* The real requantization of the mltcoefs
*
* @param q pointer to the COOKContext
* @param index index
* @param quant_index quantisation index
* @param subband_coef_index array of indexes to quant_centroid_tab
* @param subband_coef_sign signs of coefficients
* @param mlt_p pointer into the mlt buffer
*/
static void scalar_dequant_math(COOKContext *q, int index, int quant_index,
int* subband_coef_index,
int* subband_coef_sign, FIXP *mlt_p)
{
/* Num. half bits to right shift */
const int s = 33 - quant_index + av_log2(q->samples_per_channel);
FIXP f1;
int i;
if (s >= 64) {
memset(mlt_p, 0, sizeof(FIXP) * SUBBAND_SIZE);
return;
}
for(i=0 ; i<SUBBAND_SIZE ; i++) {
if (subband_coef_index[i]) {
f1 = quant_centroid_tab[index][subband_coef_index[i]][s&1];
if (subband_coef_sign[i]) f1 = -f1;
} else {
/* noise coding if subband_coef_index[i] == 0 */
f1 = dither_tab[index][s&1];
if (av_random(&q->random_state) < 0x80000000) f1 = -f1;
}
mlt_p[i] = fixp_shr(f1, s/2);
}
}
/**
* the actual requantization of the timedomain samples
*
* @param q pointer to the COOKContext
* @param buffer pointer to the timedomain buffer
* @param gain_index index for the block multiplier
* @param gain_index_next index for the next block multiplier
*/
static inline void interpolate_math(COOKContext *q, FIXP* buffer,
int gain_index, int gain_index_next)
{
int gain_size_factor = q->samples_per_channel/8;
int i;
if(gain_index == gain_index_next){ //static gain
for(i = 0; i < gain_size_factor; i++) {
buffer[i] = fixp_pow2(buffer[i], gain_index);
}
} else { //smooth gain
int step = (gain_index_next - gain_index)
<< (7 - av_log2(gain_size_factor));
int x = 0;
for(i = 0; i < gain_size_factor; i++) {
buffer[i] = fixp_mult_pow2(buffer[i], pow128_tab[x], gain_index+1);
x += step;
gain_index += x >> 7;
x = x & 0x7f;
}
}
}
/* Include fixed point modified discrete cosine transform */
#include "cook_fixp_mdct.h"
/**
* The modulated lapped transform, this takes transform coefficients
* and transforms them into timedomain samples.
* Applies transform window and overlaps buffers.
*
* @param q pointer to the COOKContext
* @param inbuffer pointer to the mltcoefficients
* @param gain0 gain difference now/previous buffers
* @param previous_buffer pointer to the previous buffer to be used for overlapping
*/
static void imlt_math(COOKContext *q, FIXP *inbuffer,
int gain0, FIXP *previous_buffer)
{
const FIXPU *sincos_lookup = q->math.sincos_lookup;
const int n = q->samples_per_channel;
const int step = 4 << (10 - av_log2(n));
FIXP *buffer1 = q->mono_mdct_output + n;
int i = 0, j = step>>1;
cook_mdct_backward(2 * n, inbuffer, q->mono_mdct_output,
q->math.sincos_lookup);
/* Apply window and overlap */
do {
buffer1[i] =
fixp_mult_pow2(buffer1[i], sincos_lookup[j], gain0) -
fixp_mult(previous_buffer[i], sincos_lookup[j+1]);
j += step;
} while (++i < n/2);
do {
j -= step;
buffer1[i] =
fixp_mult_pow2(buffer1[i], sincos_lookup[j+1], gain0) -
fixp_mult(previous_buffer[i], sincos_lookup[j]);
} while (++i < n);
}
/**
* Decoupling calculation for joint stereo coefficients.
*
* @param x mono coefficient
* @param table number of decoupling table
* @param i table index
*/
static inline FIXP cplscale_math(FIXP x, int table, int i)
{
return fixp_mult(x, cplscales[table-2][i]);
}
/**
* Final converion from floating point values to
* signed, 16 bit sound samples. Round and clip.
*
* @param q pointer to the COOKContext
* @param out pointer to the output buffer
* @param chan 0: left or single channel, 1: right channel
*/
static inline void output_math(COOKContext *q, int16_t *out, int chan)
{
FIXP *output = q->mono_mdct_output + q->samples_per_channel;
int j;
for (j = 0; j < q->samples_per_channel; j++) {
FIXP v = fixp_shr(output[j], 11);
if ((uint32_t) v + 0x8000 > 0xffff)
v = (v >> 31) ^ 0x7fff;
out[chan + q->nb_channels * j] = v;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -