Merge pull request #33311 from SneakyFish5/update-opus
Update opus to 1.3.1 and opusfile to 0.11
This commit is contained in:
commit
ba4c808721
|
@ -20,6 +20,9 @@ if env['builtin_opus']:
|
|||
"opus_multistream.c",
|
||||
"opus_multistream_encoder.c",
|
||||
"opus_multistream_decoder.c",
|
||||
"opus_projection_encoder.c",
|
||||
"opus_projection_decoder.c",
|
||||
"mapping_matrix.c",
|
||||
"repacketizer.c",
|
||||
|
||||
"analysis.c",
|
||||
|
@ -53,9 +56,10 @@ if env['builtin_opus']:
|
|||
"celt/vq.c",
|
||||
#"celt/arm/arm_celt_map.c",
|
||||
#"celt/arm/armcpu.c",
|
||||
#"celt/arm/celt_ne10_fft.c",
|
||||
#"celt/arm/celt_ne10_mdct.c",
|
||||
#"celt/arm/celt_fft_ne10.c",
|
||||
#"celt/arm/celt_mdct_ne10.c",
|
||||
#"celt/arm/celt_neon_intr.c",
|
||||
#"celt/arm/pitch_neon_intr.c",
|
||||
|
||||
# Sync with silk_sources.mk
|
||||
"silk/CNG.c",
|
||||
|
@ -113,6 +117,7 @@ if env['builtin_opus']:
|
|||
"silk/lin2log.c",
|
||||
"silk/log2lin.c",
|
||||
"silk/LPC_analysis_filter.c",
|
||||
"silk/LPC_fit.c",
|
||||
"silk/LPC_inv_pred_gain.c",
|
||||
"silk/table_LSF_cos.c",
|
||||
"silk/NLSF2A.c",
|
||||
|
@ -150,12 +155,10 @@ if env['builtin_opus']:
|
|||
"silk/fixed/find_pitch_lags_FIX.c",
|
||||
"silk/fixed/find_pred_coefs_FIX.c",
|
||||
"silk/fixed/noise_shape_analysis_FIX.c",
|
||||
"silk/fixed/prefilter_FIX.c",
|
||||
"silk/fixed/process_gains_FIX.c",
|
||||
"silk/fixed/regularize_correlations_FIX.c",
|
||||
"silk/fixed/residual_energy16_FIX.c",
|
||||
"silk/fixed/residual_energy_FIX.c",
|
||||
"silk/fixed/solve_LS_FIX.c",
|
||||
"silk/fixed/warped_autocorrelation_FIX.c",
|
||||
"silk/fixed/apply_sine_window_FIX.c",
|
||||
"silk/fixed/autocorr_FIX.c",
|
||||
|
@ -180,11 +183,9 @@ if env['builtin_opus']:
|
|||
"silk/float/LTP_analysis_filter_FLP.c",
|
||||
"silk/float/LTP_scale_ctrl_FLP.c",
|
||||
"silk/float/noise_shape_analysis_FLP.c",
|
||||
"silk/float/prefilter_FLP.c",
|
||||
"silk/float/process_gains_FLP.c",
|
||||
"silk/float/regularize_correlations_FLP.c",
|
||||
"silk/float/residual_energy_FLP.c",
|
||||
"silk/float/solve_LS_FLP.c",
|
||||
"silk/float/warped_autocorrelation_FLP.c",
|
||||
"silk/float/wrappers_FLP.c",
|
||||
"silk/float/autocorrelation_FLP.c",
|
||||
|
@ -193,7 +194,6 @@ if env['builtin_opus']:
|
|||
"silk/float/energy_FLP.c",
|
||||
"silk/float/inner_product_FLP.c",
|
||||
"silk/float/k2a_FLP.c",
|
||||
"silk/float/levinsondurbin_FLP.c",
|
||||
"silk/float/LPC_inv_pred_gain_FLP.c",
|
||||
"silk/float/pitch_analysis_core_FLP.c",
|
||||
"silk/float/scale_copy_vector_FLP.c",
|
||||
|
|
|
@ -395,17 +395,19 @@ Files extracted from the upstream source:
|
|||
## opus
|
||||
|
||||
- Upstream: https://opus-codec.org
|
||||
- Version: 1.1.5 (opus) and 0.8 (opusfile)
|
||||
- Version: 1.3.1 (opus) and 0.11 (opusfile)
|
||||
- License: BSD-3-Clause
|
||||
|
||||
Files extracted from upstream source:
|
||||
|
||||
- Run `opus/configure` and copy/sync changes to `config.h`
|
||||
(note that this file may have Godot-specific options enabled)
|
||||
- all .c and .h files in src/ (both opus and opusfile)
|
||||
- all .h files in include/ (both opus and opusfile) as opus/
|
||||
- remove unused `opus_demo.c`,
|
||||
- remove `http.c`, `wincerts.c` and `winerrno.h` (part of
|
||||
unused libopusurl)
|
||||
- celt/ and silk/ subfolders
|
||||
- celt/ and silk/ subfolders (minus tests folders)
|
||||
- COPYING
|
||||
|
||||
|
||||
|
|
|
@ -29,20 +29,29 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define ANALYSIS_C
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "mathops.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "celt.h"
|
||||
#include "modes.h"
|
||||
#include "arch.h"
|
||||
#include "quant_bands.h"
|
||||
#include <stdio.h>
|
||||
#include "analysis.h"
|
||||
#include "mlp.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "float_cast.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
|
||||
#define TRANSITION_PENALTY 10
|
||||
|
||||
static const float dct_table[128] = {
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f, 0.250000f,
|
||||
|
@ -96,52 +105,118 @@ static const float analysis_window[240] = {
|
|||
};
|
||||
|
||||
static const int tbands[NB_TBANDS+1] = {
|
||||
2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120
|
||||
4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240
|
||||
};
|
||||
|
||||
static const int extra_bands[NB_TOT_BANDS+1] = {
|
||||
1, 2, 4, 6, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 68, 80, 96, 120, 160, 200
|
||||
};
|
||||
|
||||
/*static const float tweight[NB_TBANDS+1] = {
|
||||
.3, .4, .5, .6, .7, .8, .9, 1., 1., 1., 1., 1., 1., 1., .8, .7, .6, .5
|
||||
};*/
|
||||
|
||||
#define NB_TONAL_SKIP_BANDS 9
|
||||
|
||||
#define cA 0.43157974f
|
||||
#define cB 0.67848403f
|
||||
#define cC 0.08595542f
|
||||
#define cE ((float)M_PI/2)
|
||||
static OPUS_INLINE float fast_atan2f(float y, float x) {
|
||||
float x2, y2;
|
||||
/* Should avoid underflow on the values we'll get */
|
||||
if (ABS16(x)+ABS16(y)<1e-9f)
|
||||
{
|
||||
x*=1e12f;
|
||||
y*=1e12f;
|
||||
}
|
||||
x2 = x*x;
|
||||
y2 = y*y;
|
||||
if(x2<y2){
|
||||
float den = (y2 + cB*x2) * (y2 + cC*x2);
|
||||
if (den!=0)
|
||||
return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
|
||||
else
|
||||
return (y<0 ? -cE : cE);
|
||||
}else{
|
||||
float den = (x2 + cB*y2) * (x2 + cC*y2);
|
||||
if (den!=0)
|
||||
return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
|
||||
else
|
||||
return (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
|
||||
}
|
||||
static opus_val32 silk_resampler_down2_hp(
|
||||
opus_val32 *S, /* I/O State vector [ 2 ] */
|
||||
opus_val32 *out, /* O Output signal [ floor(len/2) ] */
|
||||
const opus_val32 *in, /* I Input signal [ len ] */
|
||||
int inLen /* I Number of input samples */
|
||||
)
|
||||
{
|
||||
int k, len2 = inLen/2;
|
||||
opus_val32 in32, out32, out32_hp, Y, X;
|
||||
opus_val64 hp_ener = 0;
|
||||
/* Internal variables and state are in Q10 format */
|
||||
for( k = 0; k < len2; k++ ) {
|
||||
/* Convert to Q10 */
|
||||
in32 = in[ 2 * k ];
|
||||
|
||||
/* All-pass section for even input sample */
|
||||
Y = SUB32( in32, S[ 0 ] );
|
||||
X = MULT16_32_Q15(QCONST16(0.6074371f, 15), Y);
|
||||
out32 = ADD32( S[ 0 ], X );
|
||||
S[ 0 ] = ADD32( in32, X );
|
||||
out32_hp = out32;
|
||||
/* Convert to Q10 */
|
||||
in32 = in[ 2 * k + 1 ];
|
||||
|
||||
/* All-pass section for odd input sample, and add to output of previous section */
|
||||
Y = SUB32( in32, S[ 1 ] );
|
||||
X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y);
|
||||
out32 = ADD32( out32, S[ 1 ] );
|
||||
out32 = ADD32( out32, X );
|
||||
S[ 1 ] = ADD32( in32, X );
|
||||
|
||||
Y = SUB32( -in32, S[ 2 ] );
|
||||
X = MULT16_32_Q15(QCONST16(0.15063f, 15), Y);
|
||||
out32_hp = ADD32( out32_hp, S[ 2 ] );
|
||||
out32_hp = ADD32( out32_hp, X );
|
||||
S[ 2 ] = ADD32( -in32, X );
|
||||
|
||||
hp_ener += out32_hp*(opus_val64)out32_hp;
|
||||
/* Add, convert back to int16 and store to output */
|
||||
out[ k ] = HALF32(out32);
|
||||
}
|
||||
#ifdef FIXED_POINT
|
||||
/* len2 can be up to 480, so we shift by 8 more to make it fit. */
|
||||
hp_ener = hp_ener >> (2*SIG_SHIFT + 8);
|
||||
#endif
|
||||
return (opus_val32)hp_ener;
|
||||
}
|
||||
|
||||
void tonality_analysis_init(TonalityAnalysisState *tonal)
|
||||
static opus_val32 downmix_and_resample(downmix_func downmix, const void *_x, opus_val32 *y, opus_val32 S[3], int subframe, int offset, int c1, int c2, int C, int Fs)
|
||||
{
|
||||
VARDECL(opus_val32, tmp);
|
||||
opus_val32 scale;
|
||||
int j;
|
||||
opus_val32 ret = 0;
|
||||
SAVE_STACK;
|
||||
|
||||
if (subframe==0) return 0;
|
||||
if (Fs == 48000)
|
||||
{
|
||||
subframe *= 2;
|
||||
offset *= 2;
|
||||
} else if (Fs == 16000) {
|
||||
subframe = subframe*2/3;
|
||||
offset = offset*2/3;
|
||||
}
|
||||
ALLOC(tmp, subframe, opus_val32);
|
||||
|
||||
downmix(_x, tmp, subframe, offset, c1, c2, C);
|
||||
#ifdef FIXED_POINT
|
||||
scale = (1<<SIG_SHIFT);
|
||||
#else
|
||||
scale = 1.f/32768;
|
||||
#endif
|
||||
if (c2==-2)
|
||||
scale /= C;
|
||||
else if (c2>-1)
|
||||
scale /= 2;
|
||||
for (j=0;j<subframe;j++)
|
||||
tmp[j] *= scale;
|
||||
if (Fs == 48000)
|
||||
{
|
||||
ret = silk_resampler_down2_hp(S, y, tmp, subframe);
|
||||
} else if (Fs == 24000) {
|
||||
OPUS_COPY(y, tmp, subframe);
|
||||
} else if (Fs == 16000) {
|
||||
VARDECL(opus_val32, tmp3x);
|
||||
ALLOC(tmp3x, 3*subframe, opus_val32);
|
||||
/* Don't do this at home! This resampler is horrible and it's only (barely)
|
||||
usable for the purpose of the analysis because we don't care about all
|
||||
the aliasing between 8 kHz and 12 kHz. */
|
||||
for (j=0;j<subframe;j++)
|
||||
{
|
||||
tmp3x[3*j] = tmp[j];
|
||||
tmp3x[3*j+1] = tmp[j];
|
||||
tmp3x[3*j+2] = tmp[j];
|
||||
}
|
||||
silk_resampler_down2_hp(S, y, tmp3x, 3*subframe);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void tonality_analysis_init(TonalityAnalysisState *tonal, opus_int32 Fs)
|
||||
{
|
||||
/* Initialize reusable fields. */
|
||||
tonal->arch = opus_select_arch();
|
||||
tonal->Fs = Fs;
|
||||
/* Clear remaining fields. */
|
||||
tonality_analysis_reset(tonal);
|
||||
}
|
||||
|
@ -157,15 +232,34 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int
|
|||
{
|
||||
int pos;
|
||||
int curr_lookahead;
|
||||
float psum;
|
||||
float tonality_max;
|
||||
float tonality_avg;
|
||||
int tonality_count;
|
||||
int i;
|
||||
int pos0;
|
||||
float prob_avg;
|
||||
float prob_count;
|
||||
float prob_min, prob_max;
|
||||
float vad_prob;
|
||||
int mpos, vpos;
|
||||
int bandwidth_span;
|
||||
|
||||
pos = tonal->read_pos;
|
||||
curr_lookahead = tonal->write_pos-tonal->read_pos;
|
||||
if (curr_lookahead<0)
|
||||
curr_lookahead += DETECT_SIZE;
|
||||
|
||||
if (len > 480 && pos != tonal->write_pos)
|
||||
tonal->read_subframe += len/(tonal->Fs/400);
|
||||
while (tonal->read_subframe>=8)
|
||||
{
|
||||
tonal->read_subframe -= 8;
|
||||
tonal->read_pos++;
|
||||
}
|
||||
if (tonal->read_pos>=DETECT_SIZE)
|
||||
tonal->read_pos-=DETECT_SIZE;
|
||||
|
||||
/* On long frames, look at the second analysis window rather than the first. */
|
||||
if (len > tonal->Fs/50 && pos != tonal->write_pos)
|
||||
{
|
||||
pos++;
|
||||
if (pos==DETECT_SIZE)
|
||||
|
@ -175,33 +269,178 @@ void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int
|
|||
pos--;
|
||||
if (pos<0)
|
||||
pos = DETECT_SIZE-1;
|
||||
pos0 = pos;
|
||||
OPUS_COPY(info_out, &tonal->info[pos], 1);
|
||||
tonal->read_subframe += len/120;
|
||||
while (tonal->read_subframe>=4)
|
||||
if (!info_out->valid)
|
||||
return;
|
||||
tonality_max = tonality_avg = info_out->tonality;
|
||||
tonality_count = 1;
|
||||
/* Look at the neighbouring frames and pick largest bandwidth found (to be safe). */
|
||||
bandwidth_span = 6;
|
||||
/* If possible, look ahead for a tone to compensate for the delay in the tone detector. */
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
tonal->read_subframe -= 4;
|
||||
tonal->read_pos++;
|
||||
pos++;
|
||||
if (pos==DETECT_SIZE)
|
||||
pos = 0;
|
||||
if (pos == tonal->write_pos)
|
||||
break;
|
||||
tonality_max = MAX32(tonality_max, tonal->info[pos].tonality);
|
||||
tonality_avg += tonal->info[pos].tonality;
|
||||
tonality_count++;
|
||||
info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth);
|
||||
bandwidth_span--;
|
||||
}
|
||||
if (tonal->read_pos>=DETECT_SIZE)
|
||||
tonal->read_pos-=DETECT_SIZE;
|
||||
pos = pos0;
|
||||
/* Look back in time to see if any has a wider bandwidth than the current frame. */
|
||||
for (i=0;i<bandwidth_span;i++)
|
||||
{
|
||||
pos--;
|
||||
if (pos < 0)
|
||||
pos = DETECT_SIZE-1;
|
||||
if (pos == tonal->write_pos)
|
||||
break;
|
||||
info_out->bandwidth = IMAX(info_out->bandwidth, tonal->info[pos].bandwidth);
|
||||
}
|
||||
info_out->tonality = MAX32(tonality_avg/tonality_count, tonality_max-.2f);
|
||||
|
||||
/* Compensate for the delay in the features themselves.
|
||||
FIXME: Need a better estimate the 10 I just made up */
|
||||
curr_lookahead = IMAX(curr_lookahead-10, 0);
|
||||
mpos = vpos = pos0;
|
||||
/* If we have enough look-ahead, compensate for the ~5-frame delay in the music prob and
|
||||
~1 frame delay in the VAD prob. */
|
||||
if (curr_lookahead > 15)
|
||||
{
|
||||
mpos += 5;
|
||||
if (mpos>=DETECT_SIZE)
|
||||
mpos -= DETECT_SIZE;
|
||||
vpos += 1;
|
||||
if (vpos>=DETECT_SIZE)
|
||||
vpos -= DETECT_SIZE;
|
||||
}
|
||||
|
||||
psum=0;
|
||||
/* Summing the probability of transition patterns that involve music at
|
||||
time (DETECT_SIZE-curr_lookahead-1) */
|
||||
for (i=0;i<DETECT_SIZE-curr_lookahead;i++)
|
||||
psum += tonal->pmusic[i];
|
||||
for (;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i];
|
||||
psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
|
||||
/*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
|
||||
/* The following calculations attempt to minimize a "badness function"
|
||||
for the transition. When switching from speech to music, the badness
|
||||
of switching at frame k is
|
||||
b_k = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T)
|
||||
where
|
||||
v_i is the activity probability (VAD) at frame i,
|
||||
p_i is the music probability at frame i
|
||||
T is the probability threshold for switching
|
||||
S is the penalty for switching during active audio rather than silence
|
||||
the current frame has index i=0
|
||||
|
||||
info_out->music_prob = psum;
|
||||
Rather than apply badness to directly decide when to switch, what we compute
|
||||
instead is the threshold for which the optimal switching point is now. When
|
||||
considering whether to switch now (frame 0) or at frame k, we have:
|
||||
S*v_0 = S*v_k + \sum_{i=0}^{k-1} v_i*(p_i - T)
|
||||
which gives us:
|
||||
T = ( \sum_{i=0}^{k-1} v_i*p_i + S*(v_k-v_0) ) / ( \sum_{i=0}^{k-1} v_i )
|
||||
We take the min threshold across all positive values of k (up to the maximum
|
||||
amount of lookahead we have) to give us the threshold for which the current
|
||||
frame is the optimal switch point.
|
||||
|
||||
The last step is that we need to consider whether we want to switch at all.
|
||||
For that we use the average of the music probability over the entire window.
|
||||
If the threshold is higher than that average we're not going to
|
||||
switch, so we compute a min with the average as well. The result of all these
|
||||
min operations is music_prob_min, which gives the threshold for switching to music
|
||||
if we're currently encoding for speech.
|
||||
|
||||
We do the exact opposite to compute music_prob_max which is used for switching
|
||||
from music to speech.
|
||||
*/
|
||||
prob_min = 1.f;
|
||||
prob_max = 0.f;
|
||||
vad_prob = tonal->info[vpos].activity_probability;
|
||||
prob_count = MAX16(.1f, vad_prob);
|
||||
prob_avg = MAX16(.1f, vad_prob)*tonal->info[mpos].music_prob;
|
||||
while (1)
|
||||
{
|
||||
float pos_vad;
|
||||
mpos++;
|
||||
if (mpos==DETECT_SIZE)
|
||||
mpos = 0;
|
||||
if (mpos == tonal->write_pos)
|
||||
break;
|
||||
vpos++;
|
||||
if (vpos==DETECT_SIZE)
|
||||
vpos = 0;
|
||||
if (vpos == tonal->write_pos)
|
||||
break;
|
||||
pos_vad = tonal->info[vpos].activity_probability;
|
||||
prob_min = MIN16((prob_avg - TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_min);
|
||||
prob_max = MAX16((prob_avg + TRANSITION_PENALTY*(vad_prob - pos_vad))/prob_count, prob_max);
|
||||
prob_count += MAX16(.1f, pos_vad);
|
||||
prob_avg += MAX16(.1f, pos_vad)*tonal->info[mpos].music_prob;
|
||||
}
|
||||
info_out->music_prob = prob_avg/prob_count;
|
||||
prob_min = MIN16(prob_avg/prob_count, prob_min);
|
||||
prob_max = MAX16(prob_avg/prob_count, prob_max);
|
||||
prob_min = MAX16(prob_min, 0.f);
|
||||
prob_max = MIN16(prob_max, 1.f);
|
||||
|
||||
/* If we don't have enough look-ahead, do our best to make a decent decision. */
|
||||
if (curr_lookahead < 10)
|
||||
{
|
||||
float pmin, pmax;
|
||||
pmin = prob_min;
|
||||
pmax = prob_max;
|
||||
pos = pos0;
|
||||
/* Look for min/max in the past. */
|
||||
for (i=0;i<IMIN(tonal->count-1, 15);i++)
|
||||
{
|
||||
pos--;
|
||||
if (pos < 0)
|
||||
pos = DETECT_SIZE-1;
|
||||
pmin = MIN16(pmin, tonal->info[pos].music_prob);
|
||||
pmax = MAX16(pmax, tonal->info[pos].music_prob);
|
||||
}
|
||||
/* Bias against switching on active audio. */
|
||||
pmin = MAX16(0.f, pmin - .1f*vad_prob);
|
||||
pmax = MIN16(1.f, pmax + .1f*vad_prob);
|
||||
prob_min += (1.f-.1f*curr_lookahead)*(pmin - prob_min);
|
||||
prob_max += (1.f-.1f*curr_lookahead)*(pmax - prob_max);
|
||||
}
|
||||
info_out->music_prob_min = prob_min;
|
||||
info_out->music_prob_max = prob_max;
|
||||
|
||||
/* printf("%f %f %f %f %f\n", prob_min, prob_max, prob_avg/prob_count, vad_prob, info_out->music_prob); */
|
||||
}
|
||||
|
||||
static const float std_feature_bias[9] = {
|
||||
5.684947f, 3.475288f, 1.770634f, 1.599784f, 3.773215f,
|
||||
2.163313f, 1.260756f, 1.116868f, 1.918795f
|
||||
};
|
||||
|
||||
#define LEAKAGE_OFFSET 2.5f
|
||||
#define LEAKAGE_SLOPE 2.f
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
/* For fixed-point, the input is +/-2^15 shifted up by SIG_SHIFT, so we need to
|
||||
compensate for that in the energy. */
|
||||
#define SCALE_COMPENS (1.f/((opus_int32)1<<(15+SIG_SHIFT)))
|
||||
#define SCALE_ENER(e) ((SCALE_COMPENS*SCALE_COMPENS)*(e))
|
||||
#else
|
||||
#define SCALE_ENER(e) (e)
|
||||
#endif
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
static int is_digital_silence32(const opus_val32* pcm, int frame_size, int channels, int lsb_depth)
|
||||
{
|
||||
int silence = 0;
|
||||
opus_val32 sample_max = 0;
|
||||
#ifdef MLP_TRAINING
|
||||
return 0;
|
||||
#endif
|
||||
sample_max = celt_maxabs32(pcm, frame_size*channels);
|
||||
|
||||
silence = (sample_max == 0);
|
||||
(void)lsb_depth;
|
||||
return silence;
|
||||
}
|
||||
#else
|
||||
#define is_digital_silence32(pcm, frame_size, channels, lsb_depth) is_digital_silence(pcm, frame_size, channels, lsb_depth)
|
||||
#endif
|
||||
|
||||
static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix)
|
||||
{
|
||||
int i, b;
|
||||
|
@ -230,24 +469,50 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
float alpha, alphaE, alphaE2;
|
||||
float frame_loudness;
|
||||
float bandwidth_mask;
|
||||
int is_masked[NB_TBANDS+1];
|
||||
int bandwidth=0;
|
||||
float maxE = 0;
|
||||
float noise_floor;
|
||||
int remaining;
|
||||
AnalysisInfo *info;
|
||||
float hp_ener;
|
||||
float tonality2[240];
|
||||
float midE[8];
|
||||
float spec_variability=0;
|
||||
float band_log2[NB_TBANDS+1];
|
||||
float leakage_from[NB_TBANDS+1];
|
||||
float leakage_to[NB_TBANDS+1];
|
||||
float layer_out[MAX_NEURONS];
|
||||
float below_max_pitch;
|
||||
float above_max_pitch;
|
||||
int is_silence;
|
||||
SAVE_STACK;
|
||||
|
||||
tonal->last_transition++;
|
||||
alpha = 1.f/IMIN(20, 1+tonal->count);
|
||||
alphaE = 1.f/IMIN(50, 1+tonal->count);
|
||||
alphaE2 = 1.f/IMIN(1000, 1+tonal->count);
|
||||
|
||||
if (tonal->count<4)
|
||||
tonal->music_prob = .5;
|
||||
kfft = celt_mode->mdct.kfft[0];
|
||||
if (tonal->count==0)
|
||||
if (!tonal->initialized)
|
||||
{
|
||||
tonal->mem_fill = 240;
|
||||
downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
|
||||
tonal->initialized = 1;
|
||||
}
|
||||
alpha = 1.f/IMIN(10, 1+tonal->count);
|
||||
alphaE = 1.f/IMIN(25, 1+tonal->count);
|
||||
/* Noise floor related decay for bandwidth detection: -2.2 dB/second */
|
||||
alphaE2 = 1.f/IMIN(100, 1+tonal->count);
|
||||
if (tonal->count <= 1) alphaE2 = 1;
|
||||
|
||||
if (tonal->Fs == 48000)
|
||||
{
|
||||
/* len and offset are now at 24 kHz. */
|
||||
len/= 2;
|
||||
offset /= 2;
|
||||
} else if (tonal->Fs == 16000) {
|
||||
len = 3*len/2;
|
||||
offset = 3*offset/2;
|
||||
}
|
||||
|
||||
kfft = celt_mode->mdct.kfft[0];
|
||||
tonal->hp_ener_accum += (float)downmix_and_resample(downmix, x,
|
||||
&tonal->inmem[tonal->mem_fill], tonal->downmix_state,
|
||||
IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C, tonal->Fs);
|
||||
if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
|
||||
{
|
||||
tonal->mem_fill += len;
|
||||
|
@ -255,10 +520,13 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
RESTORE_STACK;
|
||||
return;
|
||||
}
|
||||
hp_ener = tonal->hp_ener_accum;
|
||||
info = &tonal->info[tonal->write_pos++];
|
||||
if (tonal->write_pos>=DETECT_SIZE)
|
||||
tonal->write_pos-=DETECT_SIZE;
|
||||
|
||||
is_silence = is_digital_silence32(tonal->inmem, ANALYSIS_BUF_SIZE, 1, lsb_depth);
|
||||
|
||||
ALLOC(in, 480, kiss_fft_cpx);
|
||||
ALLOC(out, 480, kiss_fft_cpx);
|
||||
ALLOC(tonality, 240, float);
|
||||
|
@ -273,8 +541,20 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
}
|
||||
OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
|
||||
remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
|
||||
downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
|
||||
tonal->hp_ener_accum = (float)downmix_and_resample(downmix, x,
|
||||
&tonal->inmem[240], tonal->downmix_state, remaining,
|
||||
offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C, tonal->Fs);
|
||||
tonal->mem_fill = 240 + remaining;
|
||||
if (is_silence)
|
||||
{
|
||||
/* On silence, copy the previous analysis. */
|
||||
int prev_pos = tonal->write_pos-2;
|
||||
if (prev_pos < 0)
|
||||
prev_pos += DETECT_SIZE;
|
||||
OPUS_COPY(info, &tonal->info[prev_pos], 1);
|
||||
RESTORE_STACK;
|
||||
return;
|
||||
}
|
||||
opus_fft(kfft, in, out, tonal->arch);
|
||||
#ifndef FIXED_POINT
|
||||
/* If there's any NaN on the input, the entire output will be NaN, so we only need to check one value. */
|
||||
|
@ -305,24 +585,31 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
d_angle2 = angle2 - angle;
|
||||
d2_angle2 = d_angle2 - d_angle;
|
||||
|
||||
mod1 = d2_angle - (float)floor(.5+d2_angle);
|
||||
mod1 = d2_angle - (float)float2int(d2_angle);
|
||||
noisiness[i] = ABS16(mod1);
|
||||
mod1 *= mod1;
|
||||
mod1 *= mod1;
|
||||
|
||||
mod2 = d2_angle2 - (float)floor(.5+d2_angle2);
|
||||
mod2 = d2_angle2 - (float)float2int(d2_angle2);
|
||||
noisiness[i] += ABS16(mod2);
|
||||
mod2 *= mod2;
|
||||
mod2 *= mod2;
|
||||
|
||||
avg_mod = .25f*(d2A[i]+2.f*mod1+mod2);
|
||||
avg_mod = .25f*(d2A[i]+mod1+2*mod2);
|
||||
/* This introduces an extra delay of 2 frames in the detection. */
|
||||
tonality[i] = 1.f/(1.f+40.f*16.f*pi4*avg_mod)-.015f;
|
||||
/* No delay on this detection, but it's less reliable. */
|
||||
tonality2[i] = 1.f/(1.f+40.f*16.f*pi4*mod2)-.015f;
|
||||
|
||||
A[i] = angle2;
|
||||
dA[i] = d_angle2;
|
||||
d2A[i] = mod2;
|
||||
}
|
||||
|
||||
for (i=2;i<N2-1;i++)
|
||||
{
|
||||
float tt = MIN32(tonality2[i], MAX32(tonality2[i-1], tonality2[i+1]));
|
||||
tonality[i] = .9f*MAX32(tonality[i], tt-.1f);
|
||||
}
|
||||
frame_tonality = 0;
|
||||
max_frame_tonality = 0;
|
||||
/*tw_sum = 0;*/
|
||||
|
@ -339,6 +626,22 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
}
|
||||
relativeE = 0;
|
||||
frame_loudness = 0;
|
||||
/* The energy of the very first band is special because of DC. */
|
||||
{
|
||||
float E = 0;
|
||||
float X1r, X2r;
|
||||
X1r = 2*(float)out[0].r;
|
||||
X2r = 2*(float)out[0].i;
|
||||
E = X1r*X1r + X2r*X2r;
|
||||
for (i=1;i<4;i++)
|
||||
{
|
||||
float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
|
||||
+ out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
|
||||
E += binE;
|
||||
}
|
||||
E = SCALE_ENER(E);
|
||||
band_log2[0] = .5f*1.442695f*(float)log(E+1e-10f);
|
||||
}
|
||||
for (b=0;b<NB_TBANDS;b++)
|
||||
{
|
||||
float E=0, tE=0, nE=0;
|
||||
|
@ -348,12 +651,9 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
{
|
||||
float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
|
||||
+ out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
|
||||
#ifdef FIXED_POINT
|
||||
/* FIXME: It's probably best to change the BFCC filter initial state instead */
|
||||
binE *= 5.55e-17f;
|
||||
#endif
|
||||
binE = SCALE_ENER(binE);
|
||||
E += binE;
|
||||
tE += binE*tonality[i];
|
||||
tE += binE*MAX32(0, tonality[i]);
|
||||
nE += binE*2.f*(.5f-noisiness[i]);
|
||||
}
|
||||
#ifndef FIXED_POINT
|
||||
|
@ -371,14 +671,27 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
|
||||
frame_loudness += (float)sqrt(E+1e-10f);
|
||||
logE[b] = (float)log(E+1e-10f);
|
||||
tonal->lowE[b] = MIN32(logE[b], tonal->lowE[b]+.01f);
|
||||
tonal->highE[b] = MAX32(logE[b], tonal->highE[b]-.1f);
|
||||
if (tonal->highE[b] < tonal->lowE[b]+1.f)
|
||||
band_log2[b+1] = .5f*1.442695f*(float)log(E+1e-10f);
|
||||
tonal->logE[tonal->E_count][b] = logE[b];
|
||||
if (tonal->count==0)
|
||||
tonal->highE[b] = tonal->lowE[b] = logE[b];
|
||||
if (tonal->highE[b] > tonal->lowE[b] + 7.5)
|
||||
{
|
||||
tonal->highE[b]+=.5f;
|
||||
tonal->lowE[b]-=.5f;
|
||||
if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b])
|
||||
tonal->highE[b] -= .01f;
|
||||
else
|
||||
tonal->lowE[b] += .01f;
|
||||
}
|
||||
relativeE += (logE[b]-tonal->lowE[b])/(1e-15f+tonal->highE[b]-tonal->lowE[b]);
|
||||
if (logE[b] > tonal->highE[b])
|
||||
{
|
||||
tonal->highE[b] = logE[b];
|
||||
tonal->lowE[b] = MAX32(tonal->highE[b]-15, tonal->lowE[b]);
|
||||
} else if (logE[b] < tonal->lowE[b])
|
||||
{
|
||||
tonal->lowE[b] = logE[b];
|
||||
tonal->highE[b] = MIN32(tonal->lowE[b]+15, tonal->highE[b]);
|
||||
}
|
||||
relativeE += (logE[b]-tonal->lowE[b])/(1e-5f + (tonal->highE[b]-tonal->lowE[b]));
|
||||
|
||||
L1=L2=0;
|
||||
for (i=0;i<NB_FRAMES;i++)
|
||||
|
@ -410,45 +723,135 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
tonal->prev_band_tonality[b] = band_tonality[b];
|
||||
}
|
||||
|
||||
leakage_from[0] = band_log2[0];
|
||||
leakage_to[0] = band_log2[0] - LEAKAGE_OFFSET;
|
||||
for (b=1;b<NB_TBANDS+1;b++)
|
||||
{
|
||||
float leak_slope = LEAKAGE_SLOPE*(tbands[b]-tbands[b-1])/4;
|
||||
leakage_from[b] = MIN16(leakage_from[b-1]+leak_slope, band_log2[b]);
|
||||
leakage_to[b] = MAX16(leakage_to[b-1]-leak_slope, band_log2[b]-LEAKAGE_OFFSET);
|
||||
}
|
||||
for (b=NB_TBANDS-2;b>=0;b--)
|
||||
{
|
||||
float leak_slope = LEAKAGE_SLOPE*(tbands[b+1]-tbands[b])/4;
|
||||
leakage_from[b] = MIN16(leakage_from[b+1]+leak_slope, leakage_from[b]);
|
||||
leakage_to[b] = MAX16(leakage_to[b+1]-leak_slope, leakage_to[b]);
|
||||
}
|
||||
celt_assert(NB_TBANDS+1 <= LEAK_BANDS);
|
||||
for (b=0;b<NB_TBANDS+1;b++)
|
||||
{
|
||||
/* leak_boost[] is made up of two terms. The first, based on leakage_to[],
|
||||
represents the boost needed to overcome the amount of analysis leakage
|
||||
cause in a weaker band b by louder neighbouring bands.
|
||||
The second, based on leakage_from[], applies to a loud band b for
|
||||
which the quantization noise causes synthesis leakage to the weaker
|
||||
neighbouring bands. */
|
||||
float boost = MAX16(0, leakage_to[b] - band_log2[b]) +
|
||||
MAX16(0, band_log2[b] - (leakage_from[b]+LEAKAGE_OFFSET));
|
||||
info->leak_boost[b] = IMIN(255, (int)floor(.5 + 64.f*boost));
|
||||
}
|
||||
for (;b<LEAK_BANDS;b++) info->leak_boost[b] = 0;
|
||||
|
||||
for (i=0;i<NB_FRAMES;i++)
|
||||
{
|
||||
int j;
|
||||
float mindist = 1e15f;
|
||||
for (j=0;j<NB_FRAMES;j++)
|
||||
{
|
||||
int k;
|
||||
float dist=0;
|
||||
for (k=0;k<NB_TBANDS;k++)
|
||||
{
|
||||
float tmp;
|
||||
tmp = tonal->logE[i][k] - tonal->logE[j][k];
|
||||
dist += tmp*tmp;
|
||||
}
|
||||
if (j!=i)
|
||||
mindist = MIN32(mindist, dist);
|
||||
}
|
||||
spec_variability += mindist;
|
||||
}
|
||||
spec_variability = (float)sqrt(spec_variability/NB_FRAMES/NB_TBANDS);
|
||||
bandwidth_mask = 0;
|
||||
bandwidth = 0;
|
||||
maxE = 0;
|
||||
noise_floor = 5.7e-4f/(1<<(IMAX(0,lsb_depth-8)));
|
||||
#ifdef FIXED_POINT
|
||||
noise_floor *= 1<<(15+SIG_SHIFT);
|
||||
#endif
|
||||
noise_floor *= noise_floor;
|
||||
for (b=0;b<NB_TOT_BANDS;b++)
|
||||
below_max_pitch=0;
|
||||
above_max_pitch=0;
|
||||
for (b=0;b<NB_TBANDS;b++)
|
||||
{
|
||||
float E=0;
|
||||
float Em;
|
||||
int band_start, band_end;
|
||||
/* Keep a margin of 300 Hz for aliasing */
|
||||
band_start = extra_bands[b];
|
||||
band_end = extra_bands[b+1];
|
||||
band_start = tbands[b];
|
||||
band_end = tbands[b+1];
|
||||
for (i=band_start;i<band_end;i++)
|
||||
{
|
||||
float binE = out[i].r*(float)out[i].r + out[N-i].r*(float)out[N-i].r
|
||||
+ out[i].i*(float)out[i].i + out[N-i].i*(float)out[N-i].i;
|
||||
E += binE;
|
||||
}
|
||||
E = SCALE_ENER(E);
|
||||
maxE = MAX32(maxE, E);
|
||||
if (band_start < 64)
|
||||
{
|
||||
below_max_pitch += E;
|
||||
} else {
|
||||
above_max_pitch += E;
|
||||
}
|
||||
tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
|
||||
E = MAX32(E, tonal->meanE[b]);
|
||||
/* Use a simple follower with 13 dB/Bark slope for spreading function */
|
||||
bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
|
||||
Em = MAX32(E, tonal->meanE[b]);
|
||||
/* Consider the band "active" only if all these conditions are met:
|
||||
1) less than 10 dB below the simple follower
|
||||
2) less than 90 dB below the peak band (maximal masking possible considering
|
||||
1) less than 90 dB below the peak band (maximal masking possible considering
|
||||
both the ATH and the loudness-dependent slope of the spreading function)
|
||||
3) above the PCM quantization noise floor
|
||||
2) above the PCM quantization noise floor
|
||||
We use b+1 because the first CELT band isn't included in tbands[]
|
||||
*/
|
||||
if (E>.1*bandwidth_mask && E*1e9f > maxE && E > noise_floor*(band_end-band_start))
|
||||
bandwidth = b;
|
||||
if (E*1e9f > maxE && (Em > 3*noise_floor*(band_end-band_start) || E > noise_floor*(band_end-band_start)))
|
||||
bandwidth = b+1;
|
||||
/* Check if the band is masked (see below). */
|
||||
is_masked[b] = E < (tonal->prev_bandwidth >= b+1 ? .01f : .05f)*bandwidth_mask;
|
||||
/* Use a simple follower with 13 dB/Bark slope for spreading function. */
|
||||
bandwidth_mask = MAX32(.05f*bandwidth_mask, E);
|
||||
}
|
||||
/* Special case for the last two bands, for which we don't have spectrum but only
|
||||
the energy above 12 kHz. The difficulty here is that the high-pass we use
|
||||
leaks some LF energy, so we need to increase the threshold without accidentally cutting
|
||||
off the band. */
|
||||
if (tonal->Fs == 48000) {
|
||||
float noise_ratio;
|
||||
float Em;
|
||||
float E = hp_ener*(1.f/(60*60));
|
||||
noise_ratio = tonal->prev_bandwidth==20 ? 10.f : 30.f;
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
/* silk_resampler_down2_hp() shifted right by an extra 8 bits. */
|
||||
E *= 256.f*(1.f/Q15ONE)*(1.f/Q15ONE);
|
||||
#endif
|
||||
above_max_pitch += E;
|
||||
tonal->meanE[b] = MAX32((1-alphaE2)*tonal->meanE[b], E);
|
||||
Em = MAX32(E, tonal->meanE[b]);
|
||||
if (Em > 3*noise_ratio*noise_floor*160 || E > noise_ratio*noise_floor*160)
|
||||
bandwidth = 20;
|
||||
/* Check if the band is masked (see below). */
|
||||
is_masked[b] = E < (tonal->prev_bandwidth == 20 ? .01f : .05f)*bandwidth_mask;
|
||||
}
|
||||
if (above_max_pitch > below_max_pitch)
|
||||
info->max_pitch_ratio = below_max_pitch/above_max_pitch;
|
||||
else
|
||||
info->max_pitch_ratio = 1;
|
||||
/* In some cases, resampling aliasing can create a small amount of energy in the first band
|
||||
being cut. So if the last band is masked, we don't include it. */
|
||||
if (bandwidth == 20 && is_masked[NB_TBANDS])
|
||||
bandwidth-=2;
|
||||
else if (bandwidth > 0 && bandwidth <= NB_TBANDS && is_masked[bandwidth-1])
|
||||
bandwidth--;
|
||||
if (tonal->count<=2)
|
||||
bandwidth = 20;
|
||||
frame_loudness = 20*(float)log10(frame_loudness);
|
||||
tonal->Etracker = MAX32(tonal->Etracker-.03f, frame_loudness);
|
||||
tonal->Etracker = MAX32(tonal->Etracker-.003f, frame_loudness);
|
||||
tonal->lowECount *= (1-alphaE);
|
||||
if (frame_loudness < tonal->Etracker-30)
|
||||
tonal->lowECount += alphaE;
|
||||
|
@ -460,11 +863,18 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
sum += dct_table[i*16+b]*logE[b];
|
||||
BFCC[i] = sum;
|
||||
}
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
float sum=0;
|
||||
for (b=0;b<16;b++)
|
||||
sum += dct_table[i*16+b]*.5f*(tonal->highE[b]+tonal->lowE[b]);
|
||||
midE[i] = sum;
|
||||
}
|
||||
|
||||
frame_stationarity /= NB_TBANDS;
|
||||
relativeE /= NB_TBANDS;
|
||||
if (tonal->count<10)
|
||||
relativeE = .5;
|
||||
relativeE = .5f;
|
||||
frame_noisiness /= NB_TBANDS;
|
||||
#if 1
|
||||
info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
|
||||
|
@ -479,7 +889,7 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
info->tonality_slope = slope;
|
||||
|
||||
tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
|
||||
tonal->count++;
|
||||
tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX);
|
||||
info->tonality = frame_tonality;
|
||||
|
||||
for (i=0;i<4;i++)
|
||||
|
@ -498,6 +908,8 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
for (i=0;i<9;i++)
|
||||
tonal->std[i] = (1-alpha)*tonal->std[i] + alpha*features[i]*features[i];
|
||||
}
|
||||
for (i=0;i<4;i++)
|
||||
features[i] = BFCC[i]-midE[i];
|
||||
|
||||
for (i=0;i<8;i++)
|
||||
{
|
||||
|
@ -507,136 +919,31 @@ static void tonality_analysis(TonalityAnalysisState *tonal, const CELTMode *celt
|
|||
tonal->mem[i] = BFCC[i];
|
||||
}
|
||||
for (i=0;i<9;i++)
|
||||
features[11+i] = (float)sqrt(tonal->std[i]);
|
||||
features[20] = info->tonality;
|
||||
features[21] = info->activity;
|
||||
features[22] = frame_stationarity;
|
||||
features[23] = info->tonality_slope;
|
||||
features[24] = tonal->lowECount;
|
||||
features[11+i] = (float)sqrt(tonal->std[i]) - std_feature_bias[i];
|
||||
features[18] = spec_variability - 0.78f;
|
||||
features[20] = info->tonality - 0.154723f;
|
||||
features[21] = info->activity - 0.724643f;
|
||||
features[22] = frame_stationarity - 0.743717f;
|
||||
features[23] = info->tonality_slope + 0.069216f;
|
||||
features[24] = tonal->lowECount - 0.067930f;
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
mlp_process(&net, features, frame_probs);
|
||||
frame_probs[0] = .5f*(frame_probs[0]+1);
|
||||
/* Curve fitting between the MLP probability and the actual probability */
|
||||
frame_probs[0] = .01f + 1.21f*frame_probs[0]*frame_probs[0] - .23f*(float)pow(frame_probs[0], 10);
|
||||
/* Probability of active audio (as opposed to silence) */
|
||||
frame_probs[1] = .5f*frame_probs[1]+.5f;
|
||||
/* Consider that silence has a 50-50 probability. */
|
||||
frame_probs[0] = frame_probs[1]*frame_probs[0] + (1-frame_probs[1])*.5f;
|
||||
compute_dense(&layer0, layer_out, features);
|
||||
compute_gru(&layer1, tonal->rnn_state, layer_out);
|
||||
compute_dense(&layer2, frame_probs, tonal->rnn_state);
|
||||
|
||||
/*printf("%f %f ", frame_probs[0], frame_probs[1]);*/
|
||||
{
|
||||
/* Probability of state transition */
|
||||
float tau;
|
||||
/* Represents independence of the MLP probabilities, where
|
||||
beta=1 means fully independent. */
|
||||
float beta;
|
||||
/* Denormalized probability of speech (p0) and music (p1) after update */
|
||||
float p0, p1;
|
||||
/* Probabilities for "all speech" and "all music" */
|
||||
float s0, m0;
|
||||
/* Probability sum for renormalisation */
|
||||
float psum;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
float speech0;
|
||||
float music0;
|
||||
float p, q;
|
||||
/* Probability of speech or music vs noise */
|
||||
info->activity_probability = frame_probs[1];
|
||||
info->music_prob = frame_probs[0];
|
||||
|
||||
/* One transition every 3 minutes of active audio */
|
||||
tau = .00005f*frame_probs[1];
|
||||
/* Adapt beta based on how "unexpected" the new prob is */
|
||||
p = MAX16(.05f,MIN16(.95f,frame_probs[0]));
|
||||
q = MAX16(.05f,MIN16(.95f,tonal->music_prob));
|
||||
beta = .01f+.05f*ABS16(p-q)/(p*(1-q)+q*(1-p));
|
||||
/* p0 and p1 are the probabilities of speech and music at this frame
|
||||
using only information from previous frame and applying the
|
||||
state transition model */
|
||||
p0 = (1-tonal->music_prob)*(1-tau) + tonal->music_prob *tau;
|
||||
p1 = tonal->music_prob *(1-tau) + (1-tonal->music_prob)*tau;
|
||||
/* We apply the current probability with exponent beta to work around
|
||||
the fact that the probability estimates aren't independent. */
|
||||
p0 *= (float)pow(1-frame_probs[0], beta);
|
||||
p1 *= (float)pow(frame_probs[0], beta);
|
||||
/* Normalise the probabilities to get the Marokv probability of music. */
|
||||
tonal->music_prob = p1/(p0+p1);
|
||||
info->music_prob = tonal->music_prob;
|
||||
|
||||
/* This chunk of code deals with delayed decision. */
|
||||
psum=1e-20f;
|
||||
/* Instantaneous probability of speech and music, with beta pre-applied. */
|
||||
speech0 = (float)pow(1-frame_probs[0], beta);
|
||||
music0 = (float)pow(frame_probs[0], beta);
|
||||
if (tonal->count==1)
|
||||
{
|
||||
tonal->pspeech[0]=.5;
|
||||
tonal->pmusic [0]=.5;
|
||||
}
|
||||
/* Updated probability of having only speech (s0) or only music (m0),
|
||||
before considering the new observation. */
|
||||
s0 = tonal->pspeech[0] + tonal->pspeech[1];
|
||||
m0 = tonal->pmusic [0] + tonal->pmusic [1];
|
||||
/* Updates s0 and m0 with instantaneous probability. */
|
||||
tonal->pspeech[0] = s0*(1-tau)*speech0;
|
||||
tonal->pmusic [0] = m0*(1-tau)*music0;
|
||||
/* Propagate the transition probabilities */
|
||||
for (i=1;i<DETECT_SIZE-1;i++)
|
||||
{
|
||||
tonal->pspeech[i] = tonal->pspeech[i+1]*speech0;
|
||||
tonal->pmusic [i] = tonal->pmusic [i+1]*music0;
|
||||
}
|
||||
/* Probability that the latest frame is speech, when all the previous ones were music. */
|
||||
tonal->pspeech[DETECT_SIZE-1] = m0*tau*speech0;
|
||||
/* Probability that the latest frame is music, when all the previous ones were speech. */
|
||||
tonal->pmusic [DETECT_SIZE-1] = s0*tau*music0;
|
||||
|
||||
/* Renormalise probabilities to 1 */
|
||||
for (i=0;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i] + tonal->pmusic[i];
|
||||
psum = 1.f/psum;
|
||||
for (i=0;i<DETECT_SIZE;i++)
|
||||
{
|
||||
tonal->pspeech[i] *= psum;
|
||||
tonal->pmusic [i] *= psum;
|
||||
}
|
||||
psum = tonal->pmusic[0];
|
||||
for (i=1;i<DETECT_SIZE;i++)
|
||||
psum += tonal->pspeech[i];
|
||||
|
||||
/* Estimate our confidence in the speech/music decisions */
|
||||
if (frame_probs[1]>.75)
|
||||
{
|
||||
if (tonal->music_prob>.9)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.f/(++tonal->music_confidence_count);
|
||||
tonal->music_confidence_count = IMIN(tonal->music_confidence_count, 500);
|
||||
tonal->music_confidence += adapt*MAX16(-.2f,frame_probs[0]-tonal->music_confidence);
|
||||
}
|
||||
if (tonal->music_prob<.1)
|
||||
{
|
||||
float adapt;
|
||||
adapt = 1.f/(++tonal->speech_confidence_count);
|
||||
tonal->speech_confidence_count = IMIN(tonal->speech_confidence_count, 500);
|
||||
tonal->speech_confidence += adapt*MIN16(.2f,frame_probs[0]-tonal->speech_confidence);
|
||||
}
|
||||
} else {
|
||||
if (tonal->music_confidence_count==0)
|
||||
tonal->music_confidence = .9f;
|
||||
if (tonal->speech_confidence_count==0)
|
||||
tonal->speech_confidence = .1f;
|
||||
}
|
||||
}
|
||||
if (tonal->last_music != (tonal->music_prob>.5f))
|
||||
tonal->last_transition=0;
|
||||
tonal->last_music = tonal->music_prob>.5f;
|
||||
#else
|
||||
info->music_prob = 0;
|
||||
#endif
|
||||
/*for (i=0;i<25;i++)
|
||||
/*printf("%f %f %f\n", frame_probs[0], frame_probs[1], info->music_prob);*/
|
||||
#ifdef MLP_TRAINING
|
||||
for (i=0;i<25;i++)
|
||||
printf("%f ", features[i]);
|
||||
printf("\n");*/
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
info->bandwidth = bandwidth;
|
||||
tonal->prev_bandwidth = bandwidth;
|
||||
/*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
|
||||
info->noisiness = frame_noisiness;
|
||||
info->valid = 1;
|
||||
|
@ -650,23 +957,25 @@ void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, co
|
|||
int offset;
|
||||
int pcm_len;
|
||||
|
||||
analysis_frame_size -= analysis_frame_size&1;
|
||||
if (analysis_pcm != NULL)
|
||||
{
|
||||
/* Avoid overflow/wrap-around of the analysis buffer */
|
||||
analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/100, analysis_frame_size);
|
||||
analysis_frame_size = IMIN((DETECT_SIZE-5)*Fs/50, analysis_frame_size);
|
||||
|
||||
pcm_len = analysis_frame_size - analysis->analysis_offset;
|
||||
offset = analysis->analysis_offset;
|
||||
do {
|
||||
tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
|
||||
offset += 480;
|
||||
pcm_len -= 480;
|
||||
} while (pcm_len>0);
|
||||
while (pcm_len>0) {
|
||||
tonality_analysis(analysis, celt_mode, analysis_pcm, IMIN(Fs/50, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
|
||||
offset += Fs/50;
|
||||
pcm_len -= Fs/50;
|
||||
}
|
||||
analysis->analysis_offset = analysis_frame_size;
|
||||
|
||||
analysis->analysis_offset -= frame_size;
|
||||
}
|
||||
|
||||
analysis_info->valid = 0;
|
||||
tonality_get_info(analysis, analysis_info, frame_size);
|
||||
}
|
||||
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
|
|
@ -30,16 +30,24 @@
|
|||
|
||||
#include "celt.h"
|
||||
#include "opus_private.h"
|
||||
#include "mlp.h"
|
||||
|
||||
#define NB_FRAMES 8
|
||||
#define NB_TBANDS 18
|
||||
#define NB_TOT_BANDS 21
|
||||
#define ANALYSIS_BUF_SIZE 720 /* 15 ms at 48 kHz */
|
||||
#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */
|
||||
|
||||
#define DETECT_SIZE 200
|
||||
/* At that point we can stop counting frames because it no longer matters. */
|
||||
#define ANALYSIS_COUNT_MAX 10000
|
||||
|
||||
#define DETECT_SIZE 100
|
||||
|
||||
/* Uncomment this to print the MLP features on stdout. */
|
||||
/*#define MLP_TRAINING*/
|
||||
|
||||
typedef struct {
|
||||
int arch;
|
||||
int application;
|
||||
opus_int32 Fs;
|
||||
#define TONALITY_ANALYSIS_RESET_START angle
|
||||
float angle[240];
|
||||
float d_angle[240];
|
||||
|
@ -48,35 +56,27 @@ typedef struct {
|
|||
int mem_fill; /* number of usable samples in the buffer */
|
||||
float prev_band_tonality[NB_TBANDS];
|
||||
float prev_tonality;
|
||||
int prev_bandwidth;
|
||||
float E[NB_FRAMES][NB_TBANDS];
|
||||
float logE[NB_FRAMES][NB_TBANDS];
|
||||
float lowE[NB_TBANDS];
|
||||
float highE[NB_TBANDS];
|
||||
float meanE[NB_TOT_BANDS];
|
||||
float meanE[NB_TBANDS+1];
|
||||
float mem[32];
|
||||
float cmean[8];
|
||||
float std[9];
|
||||
float music_prob;
|
||||
float Etracker;
|
||||
float lowECount;
|
||||
int E_count;
|
||||
int last_music;
|
||||
int last_transition;
|
||||
int count;
|
||||
float subframe_mem[3];
|
||||
int analysis_offset;
|
||||
/** Probability of having speech for time i to DETECT_SIZE-1 (and music before).
|
||||
pspeech[0] is the probability that all frames in the window are speech. */
|
||||
float pspeech[DETECT_SIZE];
|
||||
/** Probability of having music for time i to DETECT_SIZE-1 (and speech before).
|
||||
pmusic[0] is the probability that all frames in the window are music. */
|
||||
float pmusic[DETECT_SIZE];
|
||||
float speech_confidence;
|
||||
float music_confidence;
|
||||
int speech_confidence_count;
|
||||
int music_confidence_count;
|
||||
int write_pos;
|
||||
int read_pos;
|
||||
int read_subframe;
|
||||
float hp_ener_accum;
|
||||
int initialized;
|
||||
float rnn_state[MAX_NEURONS];
|
||||
opus_val32 downmix_state[3];
|
||||
AnalysisInfo info[DETECT_SIZE];
|
||||
} TonalityAnalysisState;
|
||||
|
||||
|
@ -86,7 +86,7 @@ typedef struct {
|
|||
* not be repeated every analysis step. No allocated memory is retained
|
||||
* by the state struct, so no cleanup call is required.
|
||||
*/
|
||||
void tonality_analysis_init(TonalityAnalysisState *analysis);
|
||||
void tonality_analysis_init(TonalityAnalysisState *analysis, opus_int32 Fs);
|
||||
|
||||
/** Reset a TonalityAnalysisState stuct.
|
||||
*
|
||||
|
|
|
@ -58,12 +58,12 @@
|
|||
# define S_MUL(a,b) MULT16_32_Q15(b, a)
|
||||
|
||||
# define C_MUL(m,a,b) \
|
||||
do{ (m).r = SUB32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = ADD32(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
|
||||
do{ (m).r = SUB32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = ADD32_ovflw(S_MUL((a).r,(b).i) , S_MUL((a).i,(b).r)); }while(0)
|
||||
|
||||
# define C_MULC(m,a,b) \
|
||||
do{ (m).r = ADD32(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = SUB32(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
|
||||
do{ (m).r = ADD32_ovflw(S_MUL((a).r,(b).r) , S_MUL((a).i,(b).i)); \
|
||||
(m).i = SUB32_ovflw(S_MUL((a).i,(b).r) , S_MUL((a).r,(b).i)); }while(0)
|
||||
|
||||
# define C_MULBYSCALAR( c, s ) \
|
||||
do{ (c).r = S_MUL( (c).r , s ) ;\
|
||||
|
@ -77,17 +77,17 @@
|
|||
DIVSCALAR( (c).i , div); }while (0)
|
||||
|
||||
#define C_ADD( res, a,b)\
|
||||
do {(res).r=ADD32((a).r,(b).r); (res).i=ADD32((a).i,(b).i); \
|
||||
do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_SUB( res, a,b)\
|
||||
do {(res).r=SUB32((a).r,(b).r); (res).i=SUB32((a).i,(b).i); \
|
||||
do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \
|
||||
}while(0)
|
||||
#define C_ADDTO( res , a)\
|
||||
do {(res).r = ADD32((res).r, (a).r); (res).i = ADD32((res).i,(a).i);\
|
||||
do {(res).r = ADD32_ovflw((res).r, (a).r); (res).i = ADD32_ovflw((res).i,(a).i);\
|
||||
}while(0)
|
||||
|
||||
#define C_SUBFROM( res , a)\
|
||||
do {(res).r = ADD32((res).r,(a).r); (res).i = SUB32((res).i,(a).i); \
|
||||
do {(res).r = ADD32_ovflw((res).r,(a).r); (res).i = SUB32_ovflw((res).i,(a).i); \
|
||||
}while(0)
|
||||
|
||||
#if defined(OPUS_ARM_INLINE_ASM)
|
||||
|
|
|
@ -46,25 +46,50 @@
|
|||
# endif
|
||||
# endif
|
||||
|
||||
#if OPUS_GNUC_PREREQ(3, 0)
|
||||
#define opus_likely(x) (__builtin_expect(!!(x), 1))
|
||||
#define opus_unlikely(x) (__builtin_expect(!!(x), 0))
|
||||
#else
|
||||
#define opus_likely(x) (!!(x))
|
||||
#define opus_unlikely(x) (!!(x))
|
||||
#endif
|
||||
|
||||
#define CELT_SIG_SCALE 32768.f
|
||||
|
||||
#define celt_fatal(str) _celt_fatal(str, __FILE__, __LINE__);
|
||||
#ifdef ENABLE_ASSERTIONS
|
||||
#define CELT_FATAL(str) celt_fatal(str, __FILE__, __LINE__);
|
||||
|
||||
#if defined(ENABLE_ASSERTIONS) || defined(ENABLE_HARDENING)
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
void celt_fatal(const char *str, const char *file, int line);
|
||||
|
||||
#if defined(CELT_C) && !defined(OVERRIDE_celt_fatal)
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#ifdef __GNUC__
|
||||
__attribute__((noreturn))
|
||||
#endif
|
||||
static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
|
||||
void celt_fatal(const char *str, const char *file, int line)
|
||||
{
|
||||
fprintf (stderr, "Fatal (internal) error in %s, line %d: %s\n", file, line, str);
|
||||
abort();
|
||||
}
|
||||
#define celt_assert(cond) {if (!(cond)) {celt_fatal("assertion failed: " #cond);}}
|
||||
#define celt_assert2(cond, message) {if (!(cond)) {celt_fatal("assertion failed: " #cond "\n" message);}}
|
||||
#endif
|
||||
|
||||
#define celt_assert(cond) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond);}}
|
||||
#define celt_assert2(cond, message) {if (!(cond)) {CELT_FATAL("assertion failed: " #cond "\n" message);}}
|
||||
#define MUST_SUCCEED(call) celt_assert((call) == OPUS_OK)
|
||||
#else
|
||||
#define celt_assert(cond)
|
||||
#define celt_assert2(cond, message)
|
||||
#define MUST_SUCCEED(call) do {if((call) != OPUS_OK) {RESTORE_STACK; return OPUS_INTERNAL_ERROR;} } while (0)
|
||||
#endif
|
||||
|
||||
#if defined(ENABLE_ASSERTIONS)
|
||||
#define celt_sig_assert(cond) {if (!(cond)) {CELT_FATAL("signal assertion failed: " #cond);}}
|
||||
#else
|
||||
#define celt_sig_assert(cond)
|
||||
#endif
|
||||
|
||||
#define IMUL32(a,b) ((a)*(b))
|
||||
|
@ -93,14 +118,20 @@ static OPUS_INLINE void _celt_fatal(const char *str, const char *file, int line)
|
|||
|
||||
typedef opus_int16 opus_val16;
|
||||
typedef opus_int32 opus_val32;
|
||||
typedef opus_int64 opus_val64;
|
||||
|
||||
typedef opus_val32 celt_sig;
|
||||
typedef opus_val16 celt_norm;
|
||||
typedef opus_val32 celt_ener;
|
||||
|
||||
#define celt_isnan(x) 0
|
||||
|
||||
#define Q15ONE 32767
|
||||
|
||||
#define SIG_SHIFT 12
|
||||
/* Safe saturation value for 32-bit signals. Should be less than
|
||||
2^31*(1-0.85) to avoid blowing up on DC at deemphasis.*/
|
||||
#define SIG_SAT (300000000)
|
||||
|
||||
#define NORM_SCALING 16384
|
||||
|
||||
|
@ -129,7 +160,7 @@ static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
|||
|
||||
#ifdef OPUS_ARM_PRESUME_AARCH64_NEON_INTR
|
||||
#include "arm/fixed_arm64.h"
|
||||
#elif OPUS_ARM_INLINE_EDSP
|
||||
#elif defined (OPUS_ARM_INLINE_EDSP)
|
||||
#include "arm/fixed_armv5e.h"
|
||||
#elif defined (OPUS_ARM_INLINE_ASM)
|
||||
#include "arm/fixed_armv4.h"
|
||||
|
@ -147,6 +178,7 @@ static OPUS_INLINE opus_int16 SAT16(opus_int32 x) {
|
|||
|
||||
typedef float opus_val16;
|
||||
typedef float opus_val32;
|
||||
typedef float opus_val64;
|
||||
|
||||
typedef float celt_sig;
|
||||
typedef float celt_norm;
|
||||
|
@ -186,6 +218,7 @@ static OPUS_INLINE int celt_isnan(float x)
|
|||
|
||||
#define NEG16(x) (-(x))
|
||||
#define NEG32(x) (-(x))
|
||||
#define NEG32_ovflw(x) (-(x))
|
||||
#define EXTRACT16(x) (x)
|
||||
#define EXTEND32(x) (x)
|
||||
#define SHR16(a,shift) (a)
|
||||
|
@ -202,6 +235,7 @@ static OPUS_INLINE int celt_isnan(float x)
|
|||
#define SATURATE16(x) (x)
|
||||
|
||||
#define ROUND16(a,shift) (a)
|
||||
#define SROUND16(a,shift) (a)
|
||||
#define HALF16(x) (.5f*(x))
|
||||
#define HALF32(x) (.5f*(x))
|
||||
|
||||
|
@ -209,6 +243,8 @@ static OPUS_INLINE int celt_isnan(float x)
|
|||
#define SUB16(a,b) ((a)-(b))
|
||||
#define ADD32(a,b) ((a)+(b))
|
||||
#define SUB32(a,b) ((a)-(b))
|
||||
#define ADD32_ovflw(a,b) ((a)+(b))
|
||||
#define SUB32_ovflw(a,b) ((a)-(b))
|
||||
#define MULT16_16_16(a,b) ((a)*(b))
|
||||
#define MULT16_16(a,b) ((opus_val32)(a)*(opus_val32)(b))
|
||||
#define MAC16_16(c,a,b) ((c)+(opus_val32)(a)*(opus_val32)(b))
|
||||
|
@ -243,9 +279,9 @@ static OPUS_INLINE int celt_isnan(float x)
|
|||
|
||||
#ifndef GLOBAL_STACK_SIZE
|
||||
#ifdef FIXED_POINT
|
||||
#define GLOBAL_STACK_SIZE 100000
|
||||
#define GLOBAL_STACK_SIZE 120000
|
||||
#else
|
||||
#define GLOBAL_STACK_SIZE 100000
|
||||
#define GLOBAL_STACK_SIZE 120000
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
@ -164,11 +164,11 @@ while (<>) {
|
|||
$prefix = "";
|
||||
if ($proc)
|
||||
{
|
||||
$prefix = $prefix.sprintf("\t.type\t%s, %%function; ",$proc) unless ($apple);
|
||||
$prefix = $prefix.sprintf("\t.type\t%s, %%function", $proc) unless ($apple);
|
||||
# Make sure we $prefix isn't empty here (for the $apple case).
|
||||
# We handle mangling the label here, make sure it doesn't match
|
||||
# the label handling below (if $prefix would be empty).
|
||||
$prefix = "; ";
|
||||
$prefix = $prefix."; ";
|
||||
push(@proc_stack, $proc);
|
||||
s/^[A-Za-z_\.]\w+/$symprefix$&:/;
|
||||
}
|
||||
|
|
|
@ -35,12 +35,29 @@
|
|||
|
||||
#if defined(OPUS_HAVE_RTCD)
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
|
||||
opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N) = {
|
||||
celt_inner_prod_c, /* ARMv4 */
|
||||
celt_inner_prod_c, /* EDSP */
|
||||
celt_inner_prod_c, /* Media */
|
||||
celt_inner_prod_neon /* NEON */
|
||||
};
|
||||
|
||||
void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2) = {
|
||||
dual_inner_prod_c, /* ARMv4 */
|
||||
dual_inner_prod_c, /* EDSP */
|
||||
dual_inner_prod_c, /* Media */
|
||||
dual_inner_prod_neon /* NEON */
|
||||
};
|
||||
# endif
|
||||
|
||||
# if defined(FIXED_POINT)
|
||||
# if ((defined(OPUS_ARM_MAY_HAVE_NEON) && !defined(OPUS_ARM_PRESUME_NEON)) || \
|
||||
(defined(OPUS_ARM_MAY_HAVE_MEDIA) && !defined(OPUS_ARM_PRESUME_MEDIA)) || \
|
||||
(defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
|
||||
opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int , int) = {
|
||||
const opus_val16 *, opus_val32 *, int, int, int) = {
|
||||
celt_pitch_xcorr_c, /* ARMv4 */
|
||||
MAY_HAVE_EDSP(celt_pitch_xcorr), /* EDSP */
|
||||
MAY_HAVE_MEDIA(celt_pitch_xcorr), /* Media */
|
||||
|
@ -51,7 +68,7 @@ opus_val32 (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
|||
# else /* !FIXED_POINT */
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR)
|
||||
void (*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int, int) = {
|
||||
const opus_val16 *, opus_val32 *, int, int, int) = {
|
||||
celt_pitch_xcorr_c, /* ARMv4 */
|
||||
celt_pitch_xcorr_c, /* EDSP */
|
||||
celt_pitch_xcorr_c, /* Media */
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* Copyright (c) 2015 Xiph.Org Foundation
|
||||
Written by Viswanath Puttagunta */
|
||||
/**
|
||||
@file celt_ne10_fft.c
|
||||
@file celt_fft_ne10.c
|
||||
@brief ARM Neon optimizations for fft using NE10 library
|
||||
*/
|
||||
|
||||
|
@ -36,7 +36,6 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <NE10_init.h>
|
||||
#include <NE10_dsp.h>
|
||||
#include "os_support.h"
|
||||
#include "kiss_fft.h"
|
|
@ -1,7 +1,7 @@
|
|||
/* Copyright (c) 2015 Xiph.Org Foundation
|
||||
Written by Viswanath Puttagunta */
|
||||
/**
|
||||
@file celt_ne10_mdct.c
|
||||
@file celt_mdct_ne10.c
|
||||
@brief ARM Neon optimizations for mdct using NE10 library
|
||||
*/
|
||||
|
|
@ -191,121 +191,21 @@ static void xcorr_kernel_neon_float(const float32_t *x, const float32_t *y,
|
|||
vst1q_f32(sum, SUMM);
|
||||
}
|
||||
|
||||
/*
|
||||
* Function: xcorr_kernel_neon_float_process1
|
||||
* ---------------------------------
|
||||
* Computes single correlation values and stores in *sum
|
||||
*/
|
||||
static void xcorr_kernel_neon_float_process1(const float32_t *x,
|
||||
const float32_t *y, float32_t *sum, int len) {
|
||||
float32x4_t XX[4];
|
||||
float32x4_t YY[4];
|
||||
float32x2_t XX_2;
|
||||
float32x2_t YY_2;
|
||||
float32x4_t SUMM;
|
||||
float32x2_t SUMM_2[2];
|
||||
const float32_t *xi = x;
|
||||
const float32_t *yi = y;
|
||||
|
||||
SUMM = vdupq_n_f32(0);
|
||||
|
||||
/* Work on 16 values per iteration */
|
||||
while (len >= 16) {
|
||||
XX[0] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
XX[1] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
XX[2] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
XX[3] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
|
||||
YY[0] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
YY[1] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
YY[2] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
YY[3] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
|
||||
SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
|
||||
SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
|
||||
SUMM = vmlaq_f32(SUMM, YY[2], XX[2]);
|
||||
SUMM = vmlaq_f32(SUMM, YY[3], XX[3]);
|
||||
len -= 16;
|
||||
}
|
||||
|
||||
/* Work on 8 values */
|
||||
if (len >= 8) {
|
||||
XX[0] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
XX[1] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
|
||||
YY[0] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
YY[1] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
|
||||
SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
|
||||
SUMM = vmlaq_f32(SUMM, YY[1], XX[1]);
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
/* Work on 4 values */
|
||||
if (len >= 4) {
|
||||
XX[0] = vld1q_f32(xi);
|
||||
xi += 4;
|
||||
YY[0] = vld1q_f32(yi);
|
||||
yi += 4;
|
||||
SUMM = vmlaq_f32(SUMM, YY[0], XX[0]);
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
/* Start accumulating results */
|
||||
SUMM_2[0] = vget_low_f32(SUMM);
|
||||
if (len >= 2) {
|
||||
/* While at it, consume 2 more values if available */
|
||||
XX_2 = vld1_f32(xi);
|
||||
xi += 2;
|
||||
YY_2 = vld1_f32(yi);
|
||||
yi += 2;
|
||||
SUMM_2[0] = vmla_f32(SUMM_2[0], YY_2, XX_2);
|
||||
len -= 2;
|
||||
}
|
||||
SUMM_2[1] = vget_high_f32(SUMM);
|
||||
SUMM_2[0] = vadd_f32(SUMM_2[0], SUMM_2[1]);
|
||||
SUMM_2[0] = vpadd_f32(SUMM_2[0], SUMM_2[0]);
|
||||
/* Ok, now we have result accumulated in SUMM_2[0].0 */
|
||||
|
||||
if (len > 0) {
|
||||
/* Case when you have one value left */
|
||||
XX_2 = vld1_dup_f32(xi);
|
||||
YY_2 = vld1_dup_f32(yi);
|
||||
SUMM_2[0] = vmla_f32(SUMM_2[0], XX_2, YY_2);
|
||||
}
|
||||
|
||||
vst1_lane_f32(sum, SUMM_2[0], 0);
|
||||
}
|
||||
|
||||
void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch) {
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch) {
|
||||
int i;
|
||||
(void)arch;
|
||||
celt_assert(max_pitch > 0);
|
||||
celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||
celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||
|
||||
for (i = 0; i < (max_pitch-3); i += 4) {
|
||||
xcorr_kernel_neon_float((const float32_t *)_x, (const float32_t *)_y+i,
|
||||
(float32_t *)xcorr+i, len);
|
||||
}
|
||||
|
||||
/* In case max_pitch isn't multiple of 4
|
||||
* compute single correlation value per iteration
|
||||
*/
|
||||
/* In case max_pitch isn't a multiple of 4, do non-unrolled version. */
|
||||
for (; i < max_pitch; i++) {
|
||||
xcorr_kernel_neon_float_process1((const float32_t *)_x,
|
||||
(const float32_t *)_y+i, (float32_t *)xcorr+i, len);
|
||||
xcorr[i] = celt_inner_prod_neon(_x, _y+i, len);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -1,551 +0,0 @@
|
|||
.syntax unified
|
||||
@ Copyright (c) 2007-2008 CSIRO
|
||||
@ Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
@ Copyright (c) 2013 Parrot
|
||||
@ Written by Aurélien Zanelli
|
||||
@
|
||||
@ Redistribution and use in source and binary forms, with or without
|
||||
@ modification, are permitted provided that the following conditions
|
||||
@ are met:
|
||||
@
|
||||
@ - Redistributions of source code must retain the above copyright
|
||||
@ notice, this list of conditions and the following disclaimer.
|
||||
@
|
||||
@ - Redistributions in binary form must reproduce the above copyright
|
||||
@ notice, this list of conditions and the following disclaimer in the
|
||||
@ documentation and/or other materials provided with the distribution.
|
||||
@
|
||||
@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
@ ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
@ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
@ OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
@ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
@ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
@ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
@ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
.text; .p2align 2; .arch armv7-a
|
||||
.fpu neon
|
||||
.object_arch armv4t
|
||||
|
||||
.include "celt/arm/armopts-gnu.S"
|
||||
|
||||
.if OPUS_ARM_MAY_HAVE_EDSP
|
||||
.global celt_pitch_xcorr_edsp
|
||||
.endif
|
||||
|
||||
.if OPUS_ARM_MAY_HAVE_NEON
|
||||
.global celt_pitch_xcorr_neon
|
||||
.endif
|
||||
|
||||
.if OPUS_ARM_MAY_HAVE_NEON
|
||||
|
||||
@ Compute sum[k]=sum(x[j]*y[j+k],j=0...len-1), k=0...3
|
||||
; xcorr_kernel_neon: @ PROC
|
||||
xcorr_kernel_neon_start:
|
||||
@ input:
|
||||
@ r3 = int len
|
||||
@ r4 = opus_val16 *x
|
||||
@ r5 = opus_val16 *y
|
||||
@ q0 = opus_val32 sum[4]
|
||||
@ output:
|
||||
@ q0 = opus_val32 sum[4]
|
||||
@ preserved: r0-r3, r6-r11, d2, q4-q7, q9-q15
|
||||
@ internal usage:
|
||||
@ r12 = int j
|
||||
@ d3 = y_3|y_2|y_1|y_0
|
||||
@ q2 = y_B|y_A|y_9|y_8|y_7|y_6|y_5|y_4
|
||||
@ q3 = x_7|x_6|x_5|x_4|x_3|x_2|x_1|x_0
|
||||
@ q8 = scratch
|
||||
@
|
||||
@ Load y[0...3]
|
||||
@ This requires len>0 to always be valid (which we assert in the C code).
|
||||
VLD1.16 {d5}, [r5]!
|
||||
SUBS r12, r3, #8
|
||||
BLE xcorr_kernel_neon_process4
|
||||
@ Process 8 samples at a time.
|
||||
@ This loop loads one y value more than we actually need. Therefore we have to
|
||||
@ stop as soon as there are 8 or fewer samples left (instead of 7), to avoid
|
||||
@ reading past the end of the array.
|
||||
xcorr_kernel_neon_process8:
|
||||
@ This loop has 19 total instructions (10 cycles to issue, minimum), with
|
||||
@ - 2 cycles of ARM insrtuctions,
|
||||
@ - 10 cycles of load/store/byte permute instructions, and
|
||||
@ - 9 cycles of data processing instructions.
|
||||
@ On a Cortex A8, we dual-issue the maximum amount (9 cycles) between the
|
||||
@ latter two categories, meaning the whole loop should run in 10 cycles per
|
||||
@ iteration, barring cache misses.
|
||||
@
|
||||
@ Load x[0...7]
|
||||
VLD1.16 {d6, d7}, [r4]!
|
||||
@ Unlike VMOV, VAND is a data processsing instruction (and doesn't get
|
||||
@ assembled to VMOV, like VORR would), so it dual-issues with the prior VLD1.
|
||||
VAND d3, d5, d5
|
||||
SUBS r12, r12, #8
|
||||
@ Load y[4...11]
|
||||
VLD1.16 {d4, d5}, [r5]!
|
||||
VMLAL.S16 q0, d3, d6[0]
|
||||
VEXT.16 d16, d3, d4, #1
|
||||
VMLAL.S16 q0, d4, d7[0]
|
||||
VEXT.16 d17, d4, d5, #1
|
||||
VMLAL.S16 q0, d16, d6[1]
|
||||
VEXT.16 d16, d3, d4, #2
|
||||
VMLAL.S16 q0, d17, d7[1]
|
||||
VEXT.16 d17, d4, d5, #2
|
||||
VMLAL.S16 q0, d16, d6[2]
|
||||
VEXT.16 d16, d3, d4, #3
|
||||
VMLAL.S16 q0, d17, d7[2]
|
||||
VEXT.16 d17, d4, d5, #3
|
||||
VMLAL.S16 q0, d16, d6[3]
|
||||
VMLAL.S16 q0, d17, d7[3]
|
||||
BGT xcorr_kernel_neon_process8
|
||||
@ Process 4 samples here if we have > 4 left (still reading one extra y value).
|
||||
xcorr_kernel_neon_process4:
|
||||
ADDS r12, r12, #4
|
||||
BLE xcorr_kernel_neon_process2
|
||||
@ Load x[0...3]
|
||||
VLD1.16 d6, [r4]!
|
||||
@ Use VAND since it's a data processing instruction again.
|
||||
VAND d4, d5, d5
|
||||
SUB r12, r12, #4
|
||||
@ Load y[4...7]
|
||||
VLD1.16 d5, [r5]!
|
||||
VMLAL.S16 q0, d4, d6[0]
|
||||
VEXT.16 d16, d4, d5, #1
|
||||
VMLAL.S16 q0, d16, d6[1]
|
||||
VEXT.16 d16, d4, d5, #2
|
||||
VMLAL.S16 q0, d16, d6[2]
|
||||
VEXT.16 d16, d4, d5, #3
|
||||
VMLAL.S16 q0, d16, d6[3]
|
||||
@ Process 2 samples here if we have > 2 left (still reading one extra y value).
|
||||
xcorr_kernel_neon_process2:
|
||||
ADDS r12, r12, #2
|
||||
BLE xcorr_kernel_neon_process1
|
||||
@ Load x[0...1]
|
||||
VLD2.16 {d6[],d7[]}, [r4]!
|
||||
@ Use VAND since it's a data processing instruction again.
|
||||
VAND d4, d5, d5
|
||||
SUB r12, r12, #2
|
||||
@ Load y[4...5]
|
||||
VLD1.32 {d5[]}, [r5]!
|
||||
VMLAL.S16 q0, d4, d6
|
||||
VEXT.16 d16, d4, d5, #1
|
||||
@ Replace bottom copy of {y5,y4} in d5 with {y3,y2} from d4, using VSRI
|
||||
@ instead of VEXT, since it's a data-processing instruction.
|
||||
VSRI.64 d5, d4, #32
|
||||
VMLAL.S16 q0, d16, d7
|
||||
@ Process 1 sample using the extra y value we loaded above.
|
||||
xcorr_kernel_neon_process1:
|
||||
@ Load next *x
|
||||
VLD1.16 {d6[]}, [r4]!
|
||||
ADDS r12, r12, #1
|
||||
@ y[0...3] are left in d5 from prior iteration(s) (if any)
|
||||
VMLAL.S16 q0, d5, d6
|
||||
MOVLE pc, lr
|
||||
@ Now process 1 last sample, not reading ahead.
|
||||
@ Load last *y
|
||||
VLD1.16 {d4[]}, [r5]!
|
||||
VSRI.64 d4, d5, #16
|
||||
@ Load last *x
|
||||
VLD1.16 {d6[]}, [r4]!
|
||||
VMLAL.S16 q0, d4, d6
|
||||
MOV pc, lr
|
||||
.size xcorr_kernel_neon, .-xcorr_kernel_neon @ ENDP
|
||||
|
||||
@ opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
|
||||
@ opus_val32 *xcorr, int len, int max_pitch)
|
||||
; celt_pitch_xcorr_neon: @ PROC
|
||||
@ input:
|
||||
@ r0 = opus_val16 *_x
|
||||
@ r1 = opus_val16 *_y
|
||||
@ r2 = opus_val32 *xcorr
|
||||
@ r3 = int len
|
||||
@ output:
|
||||
@ r0 = int maxcorr
|
||||
@ internal usage:
|
||||
@ r4 = opus_val16 *x (for xcorr_kernel_neon())
|
||||
@ r5 = opus_val16 *y (for xcorr_kernel_neon())
|
||||
@ r6 = int max_pitch
|
||||
@ r12 = int j
|
||||
@ q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
|
||||
STMFD sp!, {r4-r6, lr}
|
||||
LDR r6, [sp, #16]
|
||||
VMOV.S32 q15, #1
|
||||
@ if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
|
||||
SUBS r6, r6, #4
|
||||
BLT celt_pitch_xcorr_neon_process4_done
|
||||
celt_pitch_xcorr_neon_process4:
|
||||
@ xcorr_kernel_neon parameters:
|
||||
@ r3 = len, r4 = _x, r5 = _y, q0 = {0, 0, 0, 0}
|
||||
MOV r4, r0
|
||||
MOV r5, r1
|
||||
VEOR q0, q0, q0
|
||||
@ xcorr_kernel_neon only modifies r4, r5, r12, and q0...q3.
|
||||
@ So we don't save/restore any other registers.
|
||||
BL xcorr_kernel_neon_start
|
||||
SUBS r6, r6, #4
|
||||
VST1.32 {q0}, [r2]!
|
||||
@ _y += 4
|
||||
ADD r1, r1, #8
|
||||
VMAX.S32 q15, q15, q0
|
||||
@ if (max_pitch < 4) goto celt_pitch_xcorr_neon_process4_done
|
||||
BGE celt_pitch_xcorr_neon_process4
|
||||
@ We have less than 4 sums left to compute.
|
||||
celt_pitch_xcorr_neon_process4_done:
|
||||
ADDS r6, r6, #4
|
||||
@ Reduce maxcorr to a single value
|
||||
VMAX.S32 d30, d30, d31
|
||||
VPMAX.S32 d30, d30, d30
|
||||
@ if (max_pitch <= 0) goto celt_pitch_xcorr_neon_done
|
||||
BLE celt_pitch_xcorr_neon_done
|
||||
@ Now compute each remaining sum one at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining:
|
||||
MOV r4, r0
|
||||
MOV r5, r1
|
||||
VMOV.I32 q0, #0
|
||||
SUBS r12, r3, #8
|
||||
BLT celt_pitch_xcorr_neon_process_remaining4
|
||||
@ Sum terms 8 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining_loop8:
|
||||
@ Load x[0...7]
|
||||
VLD1.16 {q1}, [r4]!
|
||||
@ Load y[0...7]
|
||||
VLD1.16 {q2}, [r5]!
|
||||
SUBS r12, r12, #8
|
||||
VMLAL.S16 q0, d4, d2
|
||||
VMLAL.S16 q0, d5, d3
|
||||
BGE celt_pitch_xcorr_neon_process_remaining_loop8
|
||||
@ Sum terms 4 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining4:
|
||||
ADDS r12, r12, #4
|
||||
BLT celt_pitch_xcorr_neon_process_remaining4_done
|
||||
@ Load x[0...3]
|
||||
VLD1.16 {d2}, [r4]!
|
||||
@ Load y[0...3]
|
||||
VLD1.16 {d3}, [r5]!
|
||||
SUB r12, r12, #4
|
||||
VMLAL.S16 q0, d3, d2
|
||||
celt_pitch_xcorr_neon_process_remaining4_done:
|
||||
@ Reduce the sum to a single value.
|
||||
VADD.S32 d0, d0, d1
|
||||
VPADDL.S32 d0, d0
|
||||
ADDS r12, r12, #4
|
||||
BLE celt_pitch_xcorr_neon_process_remaining_loop_done
|
||||
@ Sum terms 1 at a time.
|
||||
celt_pitch_xcorr_neon_process_remaining_loop1:
|
||||
VLD1.16 {d2[]}, [r4]!
|
||||
VLD1.16 {d3[]}, [r5]!
|
||||
SUBS r12, r12, #1
|
||||
VMLAL.S16 q0, d2, d3
|
||||
BGT celt_pitch_xcorr_neon_process_remaining_loop1
|
||||
celt_pitch_xcorr_neon_process_remaining_loop_done:
|
||||
VST1.32 {d0[0]}, [r2]!
|
||||
VMAX.S32 d30, d30, d0
|
||||
SUBS r6, r6, #1
|
||||
@ _y++
|
||||
ADD r1, r1, #2
|
||||
@ if (--max_pitch > 0) goto celt_pitch_xcorr_neon_process_remaining
|
||||
BGT celt_pitch_xcorr_neon_process_remaining
|
||||
celt_pitch_xcorr_neon_done:
|
||||
VMOV.32 r0, d30[0]
|
||||
LDMFD sp!, {r4-r6, pc}
|
||||
.size celt_pitch_xcorr_neon, .-celt_pitch_xcorr_neon @ ENDP
|
||||
|
||||
.endif
|
||||
|
||||
.if OPUS_ARM_MAY_HAVE_EDSP
|
||||
|
||||
@ This will get used on ARMv7 devices without NEON, so it has been optimized
|
||||
@ to take advantage of dual-issuing where possible.
|
||||
; xcorr_kernel_edsp: @ PROC
|
||||
xcorr_kernel_edsp_start:
|
||||
@ input:
|
||||
@ r3 = int len
|
||||
@ r4 = opus_val16 *_x (must be 32-bit aligned)
|
||||
@ r5 = opus_val16 *_y (must be 32-bit aligned)
|
||||
@ r6...r9 = opus_val32 sum[4]
|
||||
@ output:
|
||||
@ r6...r9 = opus_val32 sum[4]
|
||||
@ preserved: r0-r5
|
||||
@ internal usage
|
||||
@ r2 = int j
|
||||
@ r12,r14 = opus_val16 x[4]
|
||||
@ r10,r11 = opus_val16 y[4]
|
||||
STMFD sp!, {r2,r4,r5,lr}
|
||||
LDR r10, [r5], #4 @ Load y[0...1]
|
||||
SUBS r2, r3, #4 @ j = len-4
|
||||
LDR r11, [r5], #4 @ Load y[2...3]
|
||||
BLE xcorr_kernel_edsp_process4_done
|
||||
LDR r12, [r4], #4 @ Load x[0...1]
|
||||
@ Stall
|
||||
xcorr_kernel_edsp_process4:
|
||||
@ The multiplies must issue from pipeline 0, and can't dual-issue with each
|
||||
@ other. Every other instruction here dual-issues with a multiply, and is
|
||||
@ thus "free". There should be no stalls in the body of the loop.
|
||||
SMLABB r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x_0,y_0)
|
||||
LDR r14, [r4], #4 @ Load x[2...3]
|
||||
SMLABT r7, r12, r10, r7 @ sum[1] = MAC16_16(sum[1],x_0,y_1)
|
||||
SUBS r2, r2, #4 @ j-=4
|
||||
SMLABB r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x_0,y_2)
|
||||
SMLABT r9, r12, r11, r9 @ sum[3] = MAC16_16(sum[3],x_0,y_3)
|
||||
SMLATT r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x_1,y_1)
|
||||
LDR r10, [r5], #4 @ Load y[4...5]
|
||||
SMLATB r7, r12, r11, r7 @ sum[1] = MAC16_16(sum[1],x_1,y_2)
|
||||
SMLATT r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x_1,y_3)
|
||||
SMLATB r9, r12, r10, r9 @ sum[3] = MAC16_16(sum[3],x_1,y_4)
|
||||
LDRGT r12, [r4], #4 @ Load x[0...1]
|
||||
SMLABB r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],x_2,y_2)
|
||||
SMLABT r7, r14, r11, r7 @ sum[1] = MAC16_16(sum[1],x_2,y_3)
|
||||
SMLABB r8, r14, r10, r8 @ sum[2] = MAC16_16(sum[2],x_2,y_4)
|
||||
SMLABT r9, r14, r10, r9 @ sum[3] = MAC16_16(sum[3],x_2,y_5)
|
||||
SMLATT r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],x_3,y_3)
|
||||
LDR r11, [r5], #4 @ Load y[6...7]
|
||||
SMLATB r7, r14, r10, r7 @ sum[1] = MAC16_16(sum[1],x_3,y_4)
|
||||
SMLATT r8, r14, r10, r8 @ sum[2] = MAC16_16(sum[2],x_3,y_5)
|
||||
SMLATB r9, r14, r11, r9 @ sum[3] = MAC16_16(sum[3],x_3,y_6)
|
||||
BGT xcorr_kernel_edsp_process4
|
||||
xcorr_kernel_edsp_process4_done:
|
||||
ADDS r2, r2, #4
|
||||
BLE xcorr_kernel_edsp_done
|
||||
LDRH r12, [r4], #2 @ r12 = *x++
|
||||
SUBS r2, r2, #1 @ j--
|
||||
@ Stall
|
||||
SMLABB r6, r12, r10, r6 @ sum[0] = MAC16_16(sum[0],x,y_0)
|
||||
LDRHGT r14, [r4], #2 @ r14 = *x++
|
||||
SMLABT r7, r12, r10, r7 @ sum[1] = MAC16_16(sum[1],x,y_1)
|
||||
SMLABB r8, r12, r11, r8 @ sum[2] = MAC16_16(sum[2],x,y_2)
|
||||
SMLABT r9, r12, r11, r9 @ sum[3] = MAC16_16(sum[3],x,y_3)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABT r6, r14, r10, r6 @ sum[0] = MAC16_16(sum[0],x,y_1)
|
||||
SUBS r2, r2, #1 @ j--
|
||||
SMLABB r7, r14, r11, r7 @ sum[1] = MAC16_16(sum[1],x,y_2)
|
||||
LDRH r10, [r5], #2 @ r10 = y_4 = *y++
|
||||
SMLABT r8, r14, r11, r8 @ sum[2] = MAC16_16(sum[2],x,y_3)
|
||||
LDRHGT r12, [r4], #2 @ r12 = *x++
|
||||
SMLABB r9, r14, r10, r9 @ sum[3] = MAC16_16(sum[3],x,y_4)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABB r6, r12, r11, r6 @ sum[0] = MAC16_16(sum[0],tmp,y_2)
|
||||
CMP r2, #1 @ j--
|
||||
SMLABT r7, r12, r11, r7 @ sum[1] = MAC16_16(sum[1],tmp,y_3)
|
||||
LDRH r2, [r5], #2 @ r2 = y_5 = *y++
|
||||
SMLABB r8, r12, r10, r8 @ sum[2] = MAC16_16(sum[2],tmp,y_4)
|
||||
LDRHGT r14, [r4] @ r14 = *x
|
||||
SMLABB r9, r12, r2, r9 @ sum[3] = MAC16_16(sum[3],tmp,y_5)
|
||||
BLE xcorr_kernel_edsp_done
|
||||
SMLABT r6, r14, r11, r6 @ sum[0] = MAC16_16(sum[0],tmp,y_3)
|
||||
LDRH r11, [r5] @ r11 = y_6 = *y
|
||||
SMLABB r7, r14, r10, r7 @ sum[1] = MAC16_16(sum[1],tmp,y_4)
|
||||
SMLABB r8, r14, r2, r8 @ sum[2] = MAC16_16(sum[2],tmp,y_5)
|
||||
SMLABB r9, r14, r11, r9 @ sum[3] = MAC16_16(sum[3],tmp,y_6)
|
||||
xcorr_kernel_edsp_done:
|
||||
LDMFD sp!, {r2,r4,r5,pc}
|
||||
.size xcorr_kernel_edsp, .-xcorr_kernel_edsp @ ENDP
|
||||
|
||||
; celt_pitch_xcorr_edsp: @ PROC
|
||||
@ input:
|
||||
@ r0 = opus_val16 *_x (must be 32-bit aligned)
|
||||
@ r1 = opus_val16 *_y (only needs to be 16-bit aligned)
|
||||
@ r2 = opus_val32 *xcorr
|
||||
@ r3 = int len
|
||||
@ output:
|
||||
@ r0 = maxcorr
|
||||
@ internal usage
|
||||
@ r4 = opus_val16 *x
|
||||
@ r5 = opus_val16 *y
|
||||
@ r6 = opus_val32 sum0
|
||||
@ r7 = opus_val32 sum1
|
||||
@ r8 = opus_val32 sum2
|
||||
@ r9 = opus_val32 sum3
|
||||
@ r1 = int max_pitch
|
||||
@ r12 = int j
|
||||
STMFD sp!, {r4-r11, lr}
|
||||
MOV r5, r1
|
||||
LDR r1, [sp, #36]
|
||||
MOV r4, r0
|
||||
TST r5, #3
|
||||
@ maxcorr = 1
|
||||
MOV r0, #1
|
||||
BEQ celt_pitch_xcorr_edsp_process1u_done
|
||||
@ Compute one sum at the start to make y 32-bit aligned.
|
||||
SUBS r12, r3, #4
|
||||
@ r14 = sum = 0
|
||||
MOV r14, #0
|
||||
LDRH r8, [r5], #2
|
||||
BLE celt_pitch_xcorr_edsp_process1u_loop4_done
|
||||
LDR r6, [r4], #4
|
||||
MOV r8, r8, LSL #16
|
||||
celt_pitch_xcorr_edsp_process1u_loop4:
|
||||
LDR r9, [r5], #4
|
||||
SMLABT r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
|
||||
LDR r7, [r4], #4
|
||||
SMLATB r14, r6, r9, r14 @ sum = MAC16_16(sum, x_1, y_1)
|
||||
LDR r8, [r5], #4
|
||||
SMLABT r14, r7, r9, r14 @ sum = MAC16_16(sum, x_2, y_2)
|
||||
SUBS r12, r12, #4 @ j-=4
|
||||
SMLATB r14, r7, r8, r14 @ sum = MAC16_16(sum, x_3, y_3)
|
||||
LDRGT r6, [r4], #4
|
||||
BGT celt_pitch_xcorr_edsp_process1u_loop4
|
||||
MOV r8, r8, LSR #16
|
||||
celt_pitch_xcorr_edsp_process1u_loop4_done:
|
||||
ADDS r12, r12, #4
|
||||
celt_pitch_xcorr_edsp_process1u_loop1:
|
||||
LDRHGE r6, [r4], #2
|
||||
@ Stall
|
||||
SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, *x, *y)
|
||||
SUBSGE r12, r12, #1
|
||||
LDRHGT r8, [r5], #2
|
||||
BGT celt_pitch_xcorr_edsp_process1u_loop1
|
||||
@ Restore _x
|
||||
SUB r4, r4, r3, LSL #1
|
||||
@ Restore and advance _y
|
||||
SUB r5, r5, r3, LSL #1
|
||||
@ maxcorr = max(maxcorr, sum)
|
||||
CMP r0, r14
|
||||
ADD r5, r5, #2
|
||||
MOVLT r0, r14
|
||||
SUBS r1, r1, #1
|
||||
@ xcorr[i] = sum
|
||||
STR r14, [r2], #4
|
||||
BLE celt_pitch_xcorr_edsp_done
|
||||
celt_pitch_xcorr_edsp_process1u_done:
|
||||
@ if (max_pitch < 4) goto celt_pitch_xcorr_edsp_process2
|
||||
SUBS r1, r1, #4
|
||||
BLT celt_pitch_xcorr_edsp_process2
|
||||
celt_pitch_xcorr_edsp_process4:
|
||||
@ xcorr_kernel_edsp parameters:
|
||||
@ r3 = len, r4 = _x, r5 = _y, r6...r9 = sum[4] = {0, 0, 0, 0}
|
||||
MOV r6, #0
|
||||
MOV r7, #0
|
||||
MOV r8, #0
|
||||
MOV r9, #0
|
||||
BL xcorr_kernel_edsp_start @ xcorr_kernel_edsp(_x, _y+i, xcorr+i, len)
|
||||
@ maxcorr = max(maxcorr, sum0, sum1, sum2, sum3)
|
||||
CMP r0, r6
|
||||
@ _y+=4
|
||||
ADD r5, r5, #8
|
||||
MOVLT r0, r6
|
||||
CMP r0, r7
|
||||
MOVLT r0, r7
|
||||
CMP r0, r8
|
||||
MOVLT r0, r8
|
||||
CMP r0, r9
|
||||
MOVLT r0, r9
|
||||
STMIA r2!, {r6-r9}
|
||||
SUBS r1, r1, #4
|
||||
BGE celt_pitch_xcorr_edsp_process4
|
||||
celt_pitch_xcorr_edsp_process2:
|
||||
ADDS r1, r1, #2
|
||||
BLT celt_pitch_xcorr_edsp_process1a
|
||||
SUBS r12, r3, #4
|
||||
@ {r10, r11} = {sum0, sum1} = {0, 0}
|
||||
MOV r10, #0
|
||||
MOV r11, #0
|
||||
LDR r8, [r5], #4
|
||||
BLE celt_pitch_xcorr_edsp_process2_loop_done
|
||||
LDR r6, [r4], #4
|
||||
LDR r9, [r5], #4
|
||||
celt_pitch_xcorr_edsp_process2_loop4:
|
||||
SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDR r7, [r4], #4
|
||||
SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
SUBS r12, r12, #4 @ j-=4
|
||||
SMLATT r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_1, y_1)
|
||||
LDR r8, [r5], #4
|
||||
SMLATB r11, r6, r9, r11 @ sum1 = MAC16_16(sum1, x_1, y_2)
|
||||
LDRGT r6, [r4], #4
|
||||
SMLABB r10, r7, r9, r10 @ sum0 = MAC16_16(sum0, x_2, y_2)
|
||||
SMLABT r11, r7, r9, r11 @ sum1 = MAC16_16(sum1, x_2, y_3)
|
||||
SMLATT r10, r7, r9, r10 @ sum0 = MAC16_16(sum0, x_3, y_3)
|
||||
LDRGT r9, [r5], #4
|
||||
SMLATB r11, r7, r8, r11 @ sum1 = MAC16_16(sum1, x_3, y_4)
|
||||
BGT celt_pitch_xcorr_edsp_process2_loop4
|
||||
celt_pitch_xcorr_edsp_process2_loop_done:
|
||||
ADDS r12, r12, #2
|
||||
BLE celt_pitch_xcorr_edsp_process2_1
|
||||
LDR r6, [r4], #4
|
||||
@ Stall
|
||||
SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDR r9, [r5], #4
|
||||
SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
SUB r12, r12, #2
|
||||
SMLATT r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_1, y_1)
|
||||
MOV r8, r9
|
||||
SMLATB r11, r6, r9, r11 @ sum1 = MAC16_16(sum1, x_1, y_2)
|
||||
celt_pitch_xcorr_edsp_process2_1:
|
||||
LDRH r6, [r4], #2
|
||||
ADDS r12, r12, #1
|
||||
@ Stall
|
||||
SMLABB r10, r6, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_0)
|
||||
LDRHGT r7, [r4], #2
|
||||
SMLABT r11, r6, r8, r11 @ sum1 = MAC16_16(sum1, x_0, y_1)
|
||||
BLE celt_pitch_xcorr_edsp_process2_done
|
||||
LDRH r9, [r5], #2
|
||||
SMLABT r10, r7, r8, r10 @ sum0 = MAC16_16(sum0, x_0, y_1)
|
||||
SMLABB r11, r7, r9, r11 @ sum1 = MAC16_16(sum1, x_0, y_2)
|
||||
celt_pitch_xcorr_edsp_process2_done:
|
||||
@ Restore _x
|
||||
SUB r4, r4, r3, LSL #1
|
||||
@ Restore and advance _y
|
||||
SUB r5, r5, r3, LSL #1
|
||||
@ maxcorr = max(maxcorr, sum0)
|
||||
CMP r0, r10
|
||||
ADD r5, r5, #2
|
||||
MOVLT r0, r10
|
||||
SUB r1, r1, #2
|
||||
@ maxcorr = max(maxcorr, sum1)
|
||||
CMP r0, r11
|
||||
@ xcorr[i] = sum
|
||||
STR r10, [r2], #4
|
||||
MOVLT r0, r11
|
||||
STR r11, [r2], #4
|
||||
celt_pitch_xcorr_edsp_process1a:
|
||||
ADDS r1, r1, #1
|
||||
BLT celt_pitch_xcorr_edsp_done
|
||||
SUBS r12, r3, #4
|
||||
@ r14 = sum = 0
|
||||
MOV r14, #0
|
||||
BLT celt_pitch_xcorr_edsp_process1a_loop_done
|
||||
LDR r6, [r4], #4
|
||||
LDR r8, [r5], #4
|
||||
LDR r7, [r4], #4
|
||||
LDR r9, [r5], #4
|
||||
celt_pitch_xcorr_edsp_process1a_loop4:
|
||||
SMLABB r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
|
||||
SUBS r12, r12, #4 @ j-=4
|
||||
SMLATT r14, r6, r8, r14 @ sum = MAC16_16(sum, x_1, y_1)
|
||||
LDRGE r6, [r4], #4
|
||||
SMLABB r14, r7, r9, r14 @ sum = MAC16_16(sum, x_2, y_2)
|
||||
LDRGE r8, [r5], #4
|
||||
SMLATT r14, r7, r9, r14 @ sum = MAC16_16(sum, x_3, y_3)
|
||||
LDRGE r7, [r4], #4
|
||||
LDRGE r9, [r5], #4
|
||||
BGE celt_pitch_xcorr_edsp_process1a_loop4
|
||||
celt_pitch_xcorr_edsp_process1a_loop_done:
|
||||
ADDS r12, r12, #2
|
||||
LDRGE r6, [r4], #4
|
||||
LDRGE r8, [r5], #4
|
||||
@ Stall
|
||||
SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, x_0, y_0)
|
||||
SUBGE r12, r12, #2
|
||||
SMLATTGE r14, r6, r8, r14 @ sum = MAC16_16(sum, x_1, y_1)
|
||||
ADDS r12, r12, #1
|
||||
LDRHGE r6, [r4], #2
|
||||
LDRHGE r8, [r5], #2
|
||||
@ Stall
|
||||
SMLABBGE r14, r6, r8, r14 @ sum = MAC16_16(sum, *x, *y)
|
||||
@ maxcorr = max(maxcorr, sum)
|
||||
CMP r0, r14
|
||||
@ xcorr[i] = sum
|
||||
STR r14, [r2], #4
|
||||
MOVLT r0, r14
|
||||
celt_pitch_xcorr_edsp_done:
|
||||
LDMFD sp!, {r4-r11, pc}
|
||||
.size celt_pitch_xcorr_edsp, .-celt_pitch_xcorr_edsp @ ENDP
|
||||
|
||||
.endif
|
||||
|
||||
@ END:
|
||||
.section .note.GNU-stack,"",%progbits
|
|
@ -153,7 +153,7 @@ xcorr_kernel_neon_process1
|
|||
ENDP
|
||||
|
||||
; opus_val32 celt_pitch_xcorr_neon(opus_val16 *_x, opus_val16 *_y,
|
||||
; opus_val32 *xcorr, int len, int max_pitch)
|
||||
; opus_val32 *xcorr, int len, int max_pitch, int arch)
|
||||
celt_pitch_xcorr_neon PROC
|
||||
; input:
|
||||
; r0 = opus_val16 *_x
|
||||
|
@ -168,6 +168,8 @@ celt_pitch_xcorr_neon PROC
|
|||
; r6 = int max_pitch
|
||||
; r12 = int j
|
||||
; q15 = int maxcorr[4] (q15 is not used by xcorr_kernel_neon())
|
||||
; ignored:
|
||||
; int arch
|
||||
STMFD sp!, {r4-r6, lr}
|
||||
LDR r6, [sp, #16]
|
||||
VMOV.S32 q15, #1
|
||||
|
@ -358,6 +360,8 @@ celt_pitch_xcorr_edsp PROC
|
|||
; r9 = opus_val32 sum3
|
||||
; r1 = int max_pitch
|
||||
; r12 = int j
|
||||
; ignored:
|
||||
; int arch
|
||||
STMFD sp!, {r4-r11, lr}
|
||||
MOV r5, r1
|
||||
LDR r1, [sp, #36]
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
#if !defined(FFT_ARM_H)
|
||||
#define FFT_ARM_H
|
||||
|
||||
#include "config.h"
|
||||
#include "kiss_fft.h"
|
||||
|
||||
#if defined(HAVE_ARM_NE10)
|
||||
|
|
|
@ -37,7 +37,7 @@ static OPUS_INLINE opus_val32 MULT16_32_Q16_armv4(opus_val16 a, opus_val32 b)
|
|||
"#MULT16_32_Q16\n\t"
|
||||
"smull %0, %1, %2, %3\n\t"
|
||||
: "=&r"(rd_lo), "=&r"(rd_hi)
|
||||
: "%r"(b),"r"(a<<16)
|
||||
: "%r"(b),"r"(SHL32(a,16))
|
||||
);
|
||||
return rd_hi;
|
||||
}
|
||||
|
@ -54,10 +54,10 @@ static OPUS_INLINE opus_val32 MULT16_32_Q15_armv4(opus_val16 a, opus_val32 b)
|
|||
"#MULT16_32_Q15\n\t"
|
||||
"smull %0, %1, %2, %3\n\t"
|
||||
: "=&r"(rd_lo), "=&r"(rd_hi)
|
||||
: "%r"(b), "r"(a<<16)
|
||||
: "%r"(b), "r"(SHL32(a,16))
|
||||
);
|
||||
/*We intentionally don't OR in the high bit of rd_lo for speed.*/
|
||||
return rd_hi<<1;
|
||||
return SHL32(rd_hi,1);
|
||||
}
|
||||
#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv4(a, b))
|
||||
|
||||
|
|
|
@ -59,7 +59,7 @@ static OPUS_INLINE opus_val32 MULT16_32_Q15_armv5e(opus_val16 a, opus_val32 b)
|
|||
: "=r"(res)
|
||||
: "r"(b), "r"(a)
|
||||
);
|
||||
return res<<1;
|
||||
return SHL32(res,1);
|
||||
}
|
||||
#define MULT16_32_Q15(a, b) (MULT16_32_Q15_armv5e(a, b))
|
||||
|
||||
|
@ -76,7 +76,7 @@ static OPUS_INLINE opus_val32 MAC16_32_Q15_armv5e(opus_val32 c, opus_val16 a,
|
|||
"#MAC16_32_Q15\n\t"
|
||||
"smlawb %0, %1, %2, %3;\n"
|
||||
: "=r"(res)
|
||||
: "r"(b<<1), "r"(a), "r"(c)
|
||||
: "r"(SHL32(b,1)), "r"(a), "r"(c)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
#if !defined(MDCT_ARM_H)
|
||||
#define MDCT_ARM_H
|
||||
|
||||
#include "config.h"
|
||||
#include "mdct.h"
|
||||
|
||||
#if defined(HAVE_ARM_NE10)
|
||||
|
|
|
@ -30,11 +30,47 @@
|
|||
|
||||
# include "armcpu.h"
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N);
|
||||
void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01,
|
||||
const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2);
|
||||
|
||||
# if !defined(OPUS_HAVE_RTCD) && defined(OPUS_ARM_PRESUME_NEON)
|
||||
# define OVERRIDE_CELT_INNER_PROD (1)
|
||||
# define OVERRIDE_DUAL_INNER_PROD (1)
|
||||
# define celt_inner_prod(x, y, N, arch) ((void)(arch), PRESUME_NEON(celt_inner_prod)(x, y, N))
|
||||
# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), PRESUME_NEON(dual_inner_prod)(x, y01, y02, N, xy1, xy2))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(OVERRIDE_CELT_INNER_PROD)
|
||||
# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
|
||||
extern opus_val32 (*const CELT_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x, const opus_val16 *y, int N);
|
||||
# define OVERRIDE_CELT_INNER_PROD (1)
|
||||
# define celt_inner_prod(x, y, N, arch) ((*CELT_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y, N))
|
||||
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
|
||||
# define OVERRIDE_CELT_INNER_PROD (1)
|
||||
# define celt_inner_prod(x, y, N, arch) ((void)(arch), celt_inner_prod_neon(x, y, N))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if !defined(OVERRIDE_DUAL_INNER_PROD)
|
||||
# if defined(OPUS_HAVE_RTCD) && (defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
|
||||
extern void (*const DUAL_INNER_PROD_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *x,
|
||||
const opus_val16 *y01, const opus_val16 *y02, int N, opus_val32 *xy1, opus_val32 *xy2);
|
||||
# define OVERRIDE_DUAL_INNER_PROD (1)
|
||||
# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((*DUAL_INNER_PROD_IMPL[(arch)&OPUS_ARCHMASK])(x, y01, y02, N, xy1, xy2))
|
||||
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
|
||||
# define OVERRIDE_DUAL_INNER_PROD (1)
|
||||
# define dual_inner_prod(x, y01, y02, N, xy1, xy2, arch) ((void)(arch), dual_inner_prod_neon(x, y01, y02, N, xy1, xy2))
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# if defined(FIXED_POINT)
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON)
|
||||
opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch);
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_MEDIA)
|
||||
|
@ -43,7 +79,7 @@ opus_val32 celt_pitch_xcorr_neon(const opus_val16 *_x, const opus_val16 *_y,
|
|||
|
||||
# if defined(OPUS_ARM_MAY_HAVE_EDSP)
|
||||
opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch);
|
||||
# endif
|
||||
|
||||
# if defined(OPUS_HAVE_RTCD) && \
|
||||
|
@ -52,18 +88,17 @@ opus_val32 celt_pitch_xcorr_edsp(const opus_val16 *_x, const opus_val16 *_y,
|
|||
(defined(OPUS_ARM_MAY_HAVE_EDSP) && !defined(OPUS_ARM_PRESUME_EDSP)))
|
||||
extern opus_val32
|
||||
(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int, int);
|
||||
const opus_val16 *, opus_val32 *, int, int, int);
|
||||
# define OVERRIDE_PITCH_XCORR (1)
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
|
||||
xcorr, len, max_pitch))
|
||||
xcorr, len, max_pitch, arch))
|
||||
|
||||
# elif defined(OPUS_ARM_PRESUME_EDSP) || \
|
||||
defined(OPUS_ARM_PRESUME_MEDIA) || \
|
||||
defined(OPUS_ARM_PRESUME_NEON)
|
||||
# define OVERRIDE_PITCH_XCORR (1)
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((void)(arch),PRESUME_NEON(celt_pitch_xcorr)(_x, _y, xcorr, len, max_pitch))
|
||||
# define celt_pitch_xcorr (PRESUME_NEON(celt_pitch_xcorr))
|
||||
|
||||
# endif
|
||||
|
||||
|
@ -99,25 +134,24 @@ extern void (*const XCORR_KERNEL_IMPL[OPUS_ARCHMASK + 1])(
|
|||
/* Float case */
|
||||
#if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
void celt_pitch_xcorr_float_neon(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch);
|
||||
#endif
|
||||
|
||||
# if defined(OPUS_HAVE_RTCD) && \
|
||||
(defined(OPUS_ARM_MAY_HAVE_NEON_INTR) && !defined(OPUS_ARM_PRESUME_NEON_INTR))
|
||||
extern void
|
||||
(*const CELT_PITCH_XCORR_IMPL[OPUS_ARCHMASK+1])(const opus_val16 *,
|
||||
const opus_val16 *, opus_val32 *, int, int);
|
||||
const opus_val16 *, opus_val32 *, int, int, int);
|
||||
|
||||
# define OVERRIDE_PITCH_XCORR (1)
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((*CELT_PITCH_XCORR_IMPL[(arch)&OPUS_ARCHMASK])(_x, _y, \
|
||||
xcorr, len, max_pitch))
|
||||
xcorr, len, max_pitch, arch))
|
||||
|
||||
# elif defined(OPUS_ARM_PRESUME_NEON_INTR)
|
||||
|
||||
# define OVERRIDE_PITCH_XCORR (1)
|
||||
# define celt_pitch_xcorr(_x, _y, xcorr, len, max_pitch, arch) \
|
||||
((void)(arch),celt_pitch_xcorr_float_neon(_x, _y, xcorr, len, max_pitch))
|
||||
# define celt_pitch_xcorr celt_pitch_xcorr_float_neon
|
||||
|
||||
# endif
|
||||
|
||||
|
|
|
@ -0,0 +1,290 @@
|
|||
/***********************************************************************
|
||||
Copyright (c) 2017 Google Inc.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
***********************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <arm_neon.h>
|
||||
#include "pitch.h"
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy;
|
||||
int16x8_t x_s16x8, y_s16x8;
|
||||
int32x4_t xy_s32x4 = vdupq_n_s32(0);
|
||||
int64x2_t xy_s64x2;
|
||||
int64x1_t xy_s64x1;
|
||||
|
||||
for (i = 0; i < N - 7; i += 8) {
|
||||
x_s16x8 = vld1q_s16(&x[i]);
|
||||
y_s16x8 = vld1q_s16(&y[i]);
|
||||
xy_s32x4 = vmlal_s16(xy_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y_s16x8));
|
||||
xy_s32x4 = vmlal_s16(xy_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y_s16x8));
|
||||
}
|
||||
|
||||
if (N - i >= 4) {
|
||||
const int16x4_t x_s16x4 = vld1_s16(&x[i]);
|
||||
const int16x4_t y_s16x4 = vld1_s16(&y[i]);
|
||||
xy_s32x4 = vmlal_s16(xy_s32x4, x_s16x4, y_s16x4);
|
||||
i += 4;
|
||||
}
|
||||
|
||||
xy_s64x2 = vpaddlq_s32(xy_s32x4);
|
||||
xy_s64x1 = vadd_s64(vget_low_s64(xy_s64x2), vget_high_s64(xy_s64x2));
|
||||
xy = vget_lane_s32(vreinterpret_s32_s64(xy_s64x1), 0);
|
||||
|
||||
for (; i < N; i++) {
|
||||
xy = MAC16_16(xy, x[i], y[i]);
|
||||
}
|
||||
|
||||
#ifdef OPUS_CHECK_ASM
|
||||
celt_assert(celt_inner_prod_c(x, y, N) == xy);
|
||||
#endif
|
||||
|
||||
return xy;
|
||||
}
|
||||
|
||||
void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy01, xy02;
|
||||
int16x8_t x_s16x8, y01_s16x8, y02_s16x8;
|
||||
int32x4_t xy01_s32x4 = vdupq_n_s32(0);
|
||||
int32x4_t xy02_s32x4 = vdupq_n_s32(0);
|
||||
int64x2_t xy01_s64x2, xy02_s64x2;
|
||||
int64x1_t xy01_s64x1, xy02_s64x1;
|
||||
|
||||
for (i = 0; i < N - 7; i += 8) {
|
||||
x_s16x8 = vld1q_s16(&x[i]);
|
||||
y01_s16x8 = vld1q_s16(&y01[i]);
|
||||
y02_s16x8 = vld1q_s16(&y02[i]);
|
||||
xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y01_s16x8));
|
||||
xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_low_s16 (x_s16x8), vget_low_s16 (y02_s16x8));
|
||||
xy01_s32x4 = vmlal_s16(xy01_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y01_s16x8));
|
||||
xy02_s32x4 = vmlal_s16(xy02_s32x4, vget_high_s16(x_s16x8), vget_high_s16(y02_s16x8));
|
||||
}
|
||||
|
||||
if (N - i >= 4) {
|
||||
const int16x4_t x_s16x4 = vld1_s16(&x[i]);
|
||||
const int16x4_t y01_s16x4 = vld1_s16(&y01[i]);
|
||||
const int16x4_t y02_s16x4 = vld1_s16(&y02[i]);
|
||||
xy01_s32x4 = vmlal_s16(xy01_s32x4, x_s16x4, y01_s16x4);
|
||||
xy02_s32x4 = vmlal_s16(xy02_s32x4, x_s16x4, y02_s16x4);
|
||||
i += 4;
|
||||
}
|
||||
|
||||
xy01_s64x2 = vpaddlq_s32(xy01_s32x4);
|
||||
xy02_s64x2 = vpaddlq_s32(xy02_s32x4);
|
||||
xy01_s64x1 = vadd_s64(vget_low_s64(xy01_s64x2), vget_high_s64(xy01_s64x2));
|
||||
xy02_s64x1 = vadd_s64(vget_low_s64(xy02_s64x2), vget_high_s64(xy02_s64x2));
|
||||
xy01 = vget_lane_s32(vreinterpret_s32_s64(xy01_s64x1), 0);
|
||||
xy02 = vget_lane_s32(vreinterpret_s32_s64(xy02_s64x1), 0);
|
||||
|
||||
for (; i < N; i++) {
|
||||
xy01 = MAC16_16(xy01, x[i], y01[i]);
|
||||
xy02 = MAC16_16(xy02, x[i], y02[i]);
|
||||
}
|
||||
*xy1 = xy01;
|
||||
*xy2 = xy02;
|
||||
|
||||
#ifdef OPUS_CHECK_ASM
|
||||
{
|
||||
opus_val32 xy1_c, xy2_c;
|
||||
dual_inner_prod_c(x, y01, y02, N, &xy1_c, &xy2_c);
|
||||
celt_assert(xy1_c == *xy1);
|
||||
celt_assert(xy2_c == *xy2);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#else /* !FIXED_POINT */
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
#ifdef OPUS_CHECK_ASM
|
||||
|
||||
/* This part of code simulates floating-point NEON operations. */
|
||||
|
||||
/* celt_inner_prod_neon_float_c_simulation() simulates the floating-point */
|
||||
/* operations of celt_inner_prod_neon(), and both functions should have bit */
|
||||
/* exact output. */
|
||||
static opus_val32 celt_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y, int N)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy, xy0 = 0, xy1 = 0, xy2 = 0, xy3 = 0;
|
||||
for (i = 0; i < N - 3; i += 4) {
|
||||
xy0 = MAC16_16(xy0, x[i + 0], y[i + 0]);
|
||||
xy1 = MAC16_16(xy1, x[i + 1], y[i + 1]);
|
||||
xy2 = MAC16_16(xy2, x[i + 2], y[i + 2]);
|
||||
xy3 = MAC16_16(xy3, x[i + 3], y[i + 3]);
|
||||
}
|
||||
xy0 += xy2;
|
||||
xy1 += xy3;
|
||||
xy = xy0 + xy1;
|
||||
for (; i < N; i++) {
|
||||
xy = MAC16_16(xy, x[i], y[i]);
|
||||
}
|
||||
return xy;
|
||||
}
|
||||
|
||||
/* dual_inner_prod_neon_float_c_simulation() simulates the floating-point */
|
||||
/* operations of dual_inner_prod_neon(), and both functions should have bit */
|
||||
/* exact output. */
|
||||
static void dual_inner_prod_neon_float_c_simulation(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy01, xy02, xy01_0 = 0, xy01_1 = 0, xy01_2 = 0, xy01_3 = 0, xy02_0 = 0, xy02_1 = 0, xy02_2 = 0, xy02_3 = 0;
|
||||
for (i = 0; i < N - 3; i += 4) {
|
||||
xy01_0 = MAC16_16(xy01_0, x[i + 0], y01[i + 0]);
|
||||
xy01_1 = MAC16_16(xy01_1, x[i + 1], y01[i + 1]);
|
||||
xy01_2 = MAC16_16(xy01_2, x[i + 2], y01[i + 2]);
|
||||
xy01_3 = MAC16_16(xy01_3, x[i + 3], y01[i + 3]);
|
||||
xy02_0 = MAC16_16(xy02_0, x[i + 0], y02[i + 0]);
|
||||
xy02_1 = MAC16_16(xy02_1, x[i + 1], y02[i + 1]);
|
||||
xy02_2 = MAC16_16(xy02_2, x[i + 2], y02[i + 2]);
|
||||
xy02_3 = MAC16_16(xy02_3, x[i + 3], y02[i + 3]);
|
||||
}
|
||||
xy01_0 += xy01_2;
|
||||
xy02_0 += xy02_2;
|
||||
xy01_1 += xy01_3;
|
||||
xy02_1 += xy02_3;
|
||||
xy01 = xy01_0 + xy01_1;
|
||||
xy02 = xy02_0 + xy02_1;
|
||||
for (; i < N; i++) {
|
||||
xy01 = MAC16_16(xy01, x[i], y01[i]);
|
||||
xy02 = MAC16_16(xy02, x[i], y02[i]);
|
||||
}
|
||||
*xy1 = xy01;
|
||||
*xy2 = xy02;
|
||||
}
|
||||
|
||||
#endif /* OPUS_CHECK_ASM */
|
||||
|
||||
/* ========================================================================== */
|
||||
|
||||
opus_val32 celt_inner_prod_neon(const opus_val16 *x, const opus_val16 *y, int N)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy;
|
||||
float32x4_t xy_f32x4 = vdupq_n_f32(0);
|
||||
float32x2_t xy_f32x2;
|
||||
|
||||
for (i = 0; i < N - 7; i += 8) {
|
||||
float32x4_t x_f32x4, y_f32x4;
|
||||
x_f32x4 = vld1q_f32(&x[i]);
|
||||
y_f32x4 = vld1q_f32(&y[i]);
|
||||
xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4);
|
||||
x_f32x4 = vld1q_f32(&x[i + 4]);
|
||||
y_f32x4 = vld1q_f32(&y[i + 4]);
|
||||
xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4);
|
||||
}
|
||||
|
||||
if (N - i >= 4) {
|
||||
const float32x4_t x_f32x4 = vld1q_f32(&x[i]);
|
||||
const float32x4_t y_f32x4 = vld1q_f32(&y[i]);
|
||||
xy_f32x4 = vmlaq_f32(xy_f32x4, x_f32x4, y_f32x4);
|
||||
i += 4;
|
||||
}
|
||||
|
||||
xy_f32x2 = vadd_f32(vget_low_f32(xy_f32x4), vget_high_f32(xy_f32x4));
|
||||
xy_f32x2 = vpadd_f32(xy_f32x2, xy_f32x2);
|
||||
xy = vget_lane_f32(xy_f32x2, 0);
|
||||
|
||||
for (; i < N; i++) {
|
||||
xy = MAC16_16(xy, x[i], y[i]);
|
||||
}
|
||||
|
||||
#ifdef OPUS_CHECK_ASM
|
||||
celt_assert(ABS32(celt_inner_prod_neon_float_c_simulation(x, y, N) - xy) <= VERY_SMALL);
|
||||
#endif
|
||||
|
||||
return xy;
|
||||
}
|
||||
|
||||
void dual_inner_prod_neon(const opus_val16 *x, const opus_val16 *y01, const opus_val16 *y02,
|
||||
int N, opus_val32 *xy1, opus_val32 *xy2)
|
||||
{
|
||||
int i;
|
||||
opus_val32 xy01, xy02;
|
||||
float32x4_t xy01_f32x4 = vdupq_n_f32(0);
|
||||
float32x4_t xy02_f32x4 = vdupq_n_f32(0);
|
||||
float32x2_t xy01_f32x2, xy02_f32x2;
|
||||
|
||||
for (i = 0; i < N - 7; i += 8) {
|
||||
float32x4_t x_f32x4, y01_f32x4, y02_f32x4;
|
||||
x_f32x4 = vld1q_f32(&x[i]);
|
||||
y01_f32x4 = vld1q_f32(&y01[i]);
|
||||
y02_f32x4 = vld1q_f32(&y02[i]);
|
||||
xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4);
|
||||
xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4);
|
||||
x_f32x4 = vld1q_f32(&x[i + 4]);
|
||||
y01_f32x4 = vld1q_f32(&y01[i + 4]);
|
||||
y02_f32x4 = vld1q_f32(&y02[i + 4]);
|
||||
xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4);
|
||||
xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4);
|
||||
}
|
||||
|
||||
if (N - i >= 4) {
|
||||
const float32x4_t x_f32x4 = vld1q_f32(&x[i]);
|
||||
const float32x4_t y01_f32x4 = vld1q_f32(&y01[i]);
|
||||
const float32x4_t y02_f32x4 = vld1q_f32(&y02[i]);
|
||||
xy01_f32x4 = vmlaq_f32(xy01_f32x4, x_f32x4, y01_f32x4);
|
||||
xy02_f32x4 = vmlaq_f32(xy02_f32x4, x_f32x4, y02_f32x4);
|
||||
i += 4;
|
||||
}
|
||||
|
||||
xy01_f32x2 = vadd_f32(vget_low_f32(xy01_f32x4), vget_high_f32(xy01_f32x4));
|
||||
xy02_f32x2 = vadd_f32(vget_low_f32(xy02_f32x4), vget_high_f32(xy02_f32x4));
|
||||
xy01_f32x2 = vpadd_f32(xy01_f32x2, xy01_f32x2);
|
||||
xy02_f32x2 = vpadd_f32(xy02_f32x2, xy02_f32x2);
|
||||
xy01 = vget_lane_f32(xy01_f32x2, 0);
|
||||
xy02 = vget_lane_f32(xy02_f32x2, 0);
|
||||
|
||||
for (; i < N; i++) {
|
||||
xy01 = MAC16_16(xy01, x[i], y01[i]);
|
||||
xy02 = MAC16_16(xy02, x[i], y02[i]);
|
||||
}
|
||||
*xy1 = xy01;
|
||||
*xy2 = xy02;
|
||||
|
||||
#ifdef OPUS_CHECK_ASM
|
||||
{
|
||||
opus_val32 xy1_c, xy2_c;
|
||||
dual_inner_prod_neon_float_c_simulation(x, y01, y02, N, &xy1_c, &xy2_c);
|
||||
celt_assert(ABS32(xy1_c - *xy1) <= VERY_SMALL);
|
||||
celt_assert(ABS32(xy2_c - *xy2) <= VERY_SMALL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* FIXED_POINT */
|
|
@ -65,19 +65,19 @@ opus_uint32 celt_lcg_rand(opus_uint32 seed)
|
|||
|
||||
/* This is a cos() approximation designed to be bit-exact on any platform. Bit exactness
|
||||
with this approximation is important because it has an impact on the bit allocation */
|
||||
static opus_int16 bitexact_cos(opus_int16 x)
|
||||
opus_int16 bitexact_cos(opus_int16 x)
|
||||
{
|
||||
opus_int32 tmp;
|
||||
opus_int16 x2;
|
||||
tmp = (4096+((opus_int32)(x)*(x)))>>13;
|
||||
celt_assert(tmp<=32767);
|
||||
celt_sig_assert(tmp<=32767);
|
||||
x2 = tmp;
|
||||
x2 = (32767-x2) + FRAC_MUL16(x2, (-7651 + FRAC_MUL16(x2, (8277 + FRAC_MUL16(-626, x2)))));
|
||||
celt_assert(x2<=32766);
|
||||
celt_sig_assert(x2<=32766);
|
||||
return 1+x2;
|
||||
}
|
||||
|
||||
static int bitexact_log2tan(int isin,int icos)
|
||||
int bitexact_log2tan(int isin,int icos)
|
||||
{
|
||||
int lc;
|
||||
int ls;
|
||||
|
@ -92,10 +92,11 @@ static int bitexact_log2tan(int isin,int icos)
|
|||
|
||||
#ifdef FIXED_POINT
|
||||
/* Compute the amplitude (sqrt energy) in each of the bands */
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch)
|
||||
{
|
||||
int i, c, N;
|
||||
const opus_int16 *eBands = m->eBands;
|
||||
(void)arch;
|
||||
N = m->shortMdctSize<<LM;
|
||||
c=0; do {
|
||||
for (i=0;i<end;i++)
|
||||
|
@ -155,7 +156,7 @@ void normalise_bands(const CELTMode *m, const celt_sig * OPUS_RESTRICT freq, cel
|
|||
|
||||
#else /* FIXED_POINT */
|
||||
/* Compute the amplitude (sqrt energy) in each of the bands */
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM)
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch)
|
||||
{
|
||||
int i, c, N;
|
||||
const opus_int16 *eBands = m->eBands;
|
||||
|
@ -164,7 +165,7 @@ void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *band
|
|||
for (i=0;i<end;i++)
|
||||
{
|
||||
opus_val32 sum;
|
||||
sum = 1e-27f + celt_inner_prod_c(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM);
|
||||
sum = 1e-27f + celt_inner_prod(&X[c*N+(eBands[i]<<LM)], &X[c*N+(eBands[i]<<LM)], (eBands[i+1]-eBands[i])<<LM, arch);
|
||||
bandE[i+c*m->nbEBands] = celt_sqrt(sum);
|
||||
/*printf ("%f ", bandE[i+c*m->nbEBands]);*/
|
||||
}
|
||||
|
@ -224,9 +225,9 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
|
|||
#endif
|
||||
j=M*eBands[i];
|
||||
band_end = M*eBands[i+1];
|
||||
lg = ADD16(bandLogE[i], SHL16((opus_val16)eMeans[i],6));
|
||||
lg = SATURATE16(ADD32(bandLogE[i], SHL32((opus_val32)eMeans[i],6)));
|
||||
#ifndef FIXED_POINT
|
||||
g = celt_exp2(lg);
|
||||
g = celt_exp2(MIN32(32.f, lg));
|
||||
#else
|
||||
/* Handle the integer part of the log energy */
|
||||
shift = 16-(lg>>DB_SHIFT);
|
||||
|
@ -241,12 +242,12 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
|
|||
/* Handle extreme gains with negative shift. */
|
||||
if (shift<0)
|
||||
{
|
||||
/* For shift < -2 we'd be likely to overflow, so we're capping
|
||||
the gain here. This shouldn't happen unless the bitstream is
|
||||
already corrupted. */
|
||||
if (shift < -2)
|
||||
/* For shift <= -2 and g > 16384 we'd be likely to overflow, so we're
|
||||
capping the gain here, which is equivalent to a cap of 18 on lg.
|
||||
This shouldn't trigger unless the bitstream is already corrupted. */
|
||||
if (shift <= -2)
|
||||
{
|
||||
g = 32767;
|
||||
g = 16384;
|
||||
shift = -2;
|
||||
}
|
||||
do {
|
||||
|
@ -281,7 +282,7 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas
|
|||
|
||||
N0 = m->eBands[i+1]-m->eBands[i];
|
||||
/* depth in 1/8 bits */
|
||||
celt_assert(pulses[i]>=0);
|
||||
celt_sig_assert(pulses[i]>=0);
|
||||
depth = celt_udiv(1+pulses[i], (m->eBands[i+1]-m->eBands[i]))>>LM;
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -360,6 +361,30 @@ void anti_collapse(const CELTMode *m, celt_norm *X_, unsigned char *collapse_mas
|
|||
}
|
||||
}
|
||||
|
||||
/* Compute the weights to use for optimizing normalized distortion across
|
||||
channels. We use the amplitude to weight square distortion, which means
|
||||
that we use the square root of the value we would have been using if we
|
||||
wanted to minimize the MSE in the non-normalized domain. This roughly
|
||||
corresponds to some quick-and-dirty perceptual experiments I ran to
|
||||
measure inter-aural masking (there doesn't seem to be any published data
|
||||
on the topic). */
|
||||
static void compute_channel_weights(celt_ener Ex, celt_ener Ey, opus_val16 w[2])
|
||||
{
|
||||
celt_ener minE;
|
||||
#ifdef FIXED_POINT
|
||||
int shift;
|
||||
#endif
|
||||
minE = MIN32(Ex, Ey);
|
||||
/* Adjustment to make the weights a bit more conservative. */
|
||||
Ex = ADD32(Ex, minE/3);
|
||||
Ey = ADD32(Ey, minE/3);
|
||||
#ifdef FIXED_POINT
|
||||
shift = celt_ilog2(EPSILON+MAX32(Ex, Ey))-14;
|
||||
#endif
|
||||
w[0] = VSHR32(Ex, shift);
|
||||
w[1] = VSHR32(Ey, shift);
|
||||
}
|
||||
|
||||
static void intensity_stereo(const CELTMode *m, celt_norm * OPUS_RESTRICT X, const celt_norm * OPUS_RESTRICT Y, const celt_ener *bandE, int bandID, int N)
|
||||
{
|
||||
int i = bandID;
|
||||
|
@ -453,7 +478,7 @@ static void stereo_merge(celt_norm * OPUS_RESTRICT X, celt_norm * OPUS_RESTRICT
|
|||
/* Decide whether we should spread the pulses in the current frame */
|
||||
int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
|
||||
int last_decision, int *hf_average, int *tapset_decision, int update_hf,
|
||||
int end, int C, int M)
|
||||
int end, int C, int M, const int *spread_weight)
|
||||
{
|
||||
int i, c, N0;
|
||||
int sum = 0, nbBands=0;
|
||||
|
@ -494,8 +519,8 @@ int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
|
|||
if (i>m->nbEBands-4)
|
||||
hf_sum += celt_udiv(32*(tcount[1]+tcount[0]), N);
|
||||
tmp = (2*tcount[2] >= N) + (2*tcount[1] >= N) + (2*tcount[0] >= N);
|
||||
sum += tmp*256;
|
||||
nbBands++;
|
||||
sum += tmp*spread_weight[i];
|
||||
nbBands+=spread_weight[i];
|
||||
}
|
||||
} while (++c<C);
|
||||
|
||||
|
@ -519,7 +544,7 @@ int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
|
|||
/*printf("%d %d %d\n", hf_sum, *hf_average, *tapset_decision);*/
|
||||
celt_assert(nbBands>0); /* end has to be non-zero */
|
||||
celt_assert(sum>=0);
|
||||
sum = celt_udiv(sum, nbBands);
|
||||
sum = celt_udiv((opus_int32)sum<<8, nbBands);
|
||||
/* Recursive averaging */
|
||||
sum = (sum+*average)>>1;
|
||||
*average = sum;
|
||||
|
@ -647,6 +672,7 @@ static int compute_qn(int N, int b, int offset, int pulse_cap, int stereo)
|
|||
|
||||
struct band_ctx {
|
||||
int encode;
|
||||
int resynth;
|
||||
const CELTMode *m;
|
||||
int i;
|
||||
int intensity;
|
||||
|
@ -657,6 +683,9 @@ struct band_ctx {
|
|||
const celt_ener *bandE;
|
||||
opus_uint32 seed;
|
||||
int arch;
|
||||
int theta_round;
|
||||
int disable_inv;
|
||||
int avoid_split_noise;
|
||||
};
|
||||
|
||||
struct split_ctx {
|
||||
|
@ -714,8 +743,35 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
|
|||
if (qn!=1)
|
||||
{
|
||||
if (encode)
|
||||
itheta = (itheta*(opus_int32)qn+8192)>>14;
|
||||
|
||||
{
|
||||
if (!stereo || ctx->theta_round == 0)
|
||||
{
|
||||
itheta = (itheta*(opus_int32)qn+8192)>>14;
|
||||
if (!stereo && ctx->avoid_split_noise && itheta > 0 && itheta < qn)
|
||||
{
|
||||
/* Check if the selected value of theta will cause the bit allocation
|
||||
to inject noise on one side. If so, make sure the energy of that side
|
||||
is zero. */
|
||||
int unquantized = celt_udiv((opus_int32)itheta*16384, qn);
|
||||
imid = bitexact_cos((opus_int16)unquantized);
|
||||
iside = bitexact_cos((opus_int16)(16384-unquantized));
|
||||
delta = FRAC_MUL16((N-1)<<7,bitexact_log2tan(iside,imid));
|
||||
if (delta > *b)
|
||||
itheta = qn;
|
||||
else if (delta < -*b)
|
||||
itheta = 0;
|
||||
}
|
||||
} else {
|
||||
int down;
|
||||
/* Bias quantization towards itheta=0 and itheta=16384. */
|
||||
int bias = itheta > 8192 ? 32767/qn : -32767/qn;
|
||||
down = IMIN(qn-1, IMAX(0, (itheta*(opus_int32)qn + bias)>>14));
|
||||
if (ctx->theta_round < 0)
|
||||
itheta = down;
|
||||
else
|
||||
itheta = down+1;
|
||||
}
|
||||
}
|
||||
/* Entropy coding of the angle. We use a uniform pdf for the
|
||||
time split, a step for stereo, and a triangular one for the rest. */
|
||||
if (stereo && N>2)
|
||||
|
@ -793,7 +849,7 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
|
|||
} else if (stereo) {
|
||||
if (encode)
|
||||
{
|
||||
inv = itheta > 8192;
|
||||
inv = itheta > 8192 && !ctx->disable_inv;
|
||||
if (inv)
|
||||
{
|
||||
int j;
|
||||
|
@ -810,6 +866,9 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
|
|||
inv = ec_dec_bit_logp(ec, 2);
|
||||
} else
|
||||
inv = 0;
|
||||
/* inv flag override to avoid problems with downmixing. */
|
||||
if (ctx->disable_inv)
|
||||
inv = 0;
|
||||
itheta = 0;
|
||||
}
|
||||
qalloc = ec_tell_frac(ec) - tell;
|
||||
|
@ -845,11 +904,6 @@ static void compute_theta(struct band_ctx *ctx, struct split_ctx *sctx,
|
|||
static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y, int b,
|
||||
celt_norm *lowband_out)
|
||||
{
|
||||
#ifdef RESYNTH
|
||||
int resynth = 1;
|
||||
#else
|
||||
int resynth = !ctx->encode;
|
||||
#endif
|
||||
int c;
|
||||
int stereo;
|
||||
celt_norm *x = X;
|
||||
|
@ -874,7 +928,7 @@ static unsigned quant_band_n1(struct band_ctx *ctx, celt_norm *X, celt_norm *Y,
|
|||
ctx->remaining_bits -= 1<<BITRES;
|
||||
b-=1<<BITRES;
|
||||
}
|
||||
if (resynth)
|
||||
if (ctx->resynth)
|
||||
x[0] = sign ? -NORM_SCALING : NORM_SCALING;
|
||||
x = Y;
|
||||
} while (++c<1+stereo);
|
||||
|
@ -899,11 +953,6 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
|
|||
int B0=B;
|
||||
opus_val16 mid=0, side=0;
|
||||
unsigned cm=0;
|
||||
#ifdef RESYNTH
|
||||
int resynth = 1;
|
||||
#else
|
||||
int resynth = !ctx->encode;
|
||||
#endif
|
||||
celt_norm *Y=NULL;
|
||||
int encode;
|
||||
const CELTMode *m;
|
||||
|
@ -935,8 +984,7 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
|
|||
fill = (fill&1)|(fill<<1);
|
||||
B = (B+1)>>1;
|
||||
|
||||
compute_theta(ctx, &sctx, X, Y, N, &b, B, B0,
|
||||
LM, 0, &fill);
|
||||
compute_theta(ctx, &sctx, X, Y, N, &b, B, B0, LM, 0, &fill);
|
||||
imid = sctx.imid;
|
||||
iside = sctx.iside;
|
||||
delta = sctx.delta;
|
||||
|
@ -970,24 +1018,20 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
|
|||
rebalance = ctx->remaining_bits;
|
||||
if (mbits >= sbits)
|
||||
{
|
||||
cm = quant_partition(ctx, X, N, mbits, B,
|
||||
lowband, LM,
|
||||
cm = quant_partition(ctx, X, N, mbits, B, lowband, LM,
|
||||
MULT16_16_P15(gain,mid), fill);
|
||||
rebalance = mbits - (rebalance-ctx->remaining_bits);
|
||||
if (rebalance > 3<<BITRES && itheta!=0)
|
||||
sbits += rebalance - (3<<BITRES);
|
||||
cm |= quant_partition(ctx, Y, N, sbits, B,
|
||||
next_lowband2, LM,
|
||||
cm |= quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM,
|
||||
MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
|
||||
} else {
|
||||
cm = quant_partition(ctx, Y, N, sbits, B,
|
||||
next_lowband2, LM,
|
||||
cm = quant_partition(ctx, Y, N, sbits, B, next_lowband2, LM,
|
||||
MULT16_16_P15(gain,side), fill>>B)<<(B0>>1);
|
||||
rebalance = sbits - (rebalance-ctx->remaining_bits);
|
||||
if (rebalance > 3<<BITRES && itheta!=16384)
|
||||
mbits += rebalance - (3<<BITRES);
|
||||
cm |= quant_partition(ctx, X, N, mbits, B,
|
||||
lowband, LM,
|
||||
cm |= quant_partition(ctx, X, N, mbits, B, lowband, LM,
|
||||
MULT16_16_P15(gain,mid), fill);
|
||||
}
|
||||
} else {
|
||||
|
@ -1012,18 +1056,14 @@ static unsigned quant_partition(struct band_ctx *ctx, celt_norm *X,
|
|||
/* Finally do the actual quantization */
|
||||
if (encode)
|
||||
{
|
||||
cm = alg_quant(X, N, K, spread, B, ec
|
||||
#ifdef RESYNTH
|
||||
, gain
|
||||
#endif
|
||||
);
|
||||
cm = alg_quant(X, N, K, spread, B, ec, gain, ctx->resynth, ctx->arch);
|
||||
} else {
|
||||
cm = alg_unquant(X, N, K, spread, B, ec, gain);
|
||||
}
|
||||
} else {
|
||||
/* If there's no pulse, fill the band anyway */
|
||||
int j;
|
||||
if (resynth)
|
||||
if (ctx->resynth)
|
||||
{
|
||||
unsigned cm_mask;
|
||||
/* B can be as large as 16, so this shift might overflow an int on a
|
||||
|
@ -1080,11 +1120,6 @@ static unsigned quant_band(struct band_ctx *ctx, celt_norm *X,
|
|||
int recombine=0;
|
||||
int longBlocks;
|
||||
unsigned cm=0;
|
||||
#ifdef RESYNTH
|
||||
int resynth = 1;
|
||||
#else
|
||||
int resynth = !ctx->encode;
|
||||
#endif
|
||||
int k;
|
||||
int encode;
|
||||
int tf_change;
|
||||
|
@ -1151,11 +1186,10 @@ static unsigned quant_band(struct band_ctx *ctx, celt_norm *X,
|
|||
deinterleave_hadamard(lowband, N_B>>recombine, B0<<recombine, longBlocks);
|
||||
}
|
||||
|
||||
cm = quant_partition(ctx, X, N, b, B, lowband,
|
||||
LM, gain, fill);
|
||||
cm = quant_partition(ctx, X, N, b, B, lowband, LM, gain, fill);
|
||||
|
||||
/* This code is used by the decoder and by the resynthesis-enabled encoder */
|
||||
if (resynth)
|
||||
if (ctx->resynth)
|
||||
{
|
||||
/* Undo the sample reorganization going from time order to frequency order */
|
||||
if (B0>1)
|
||||
|
@ -1208,11 +1242,6 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
|
|||
int inv = 0;
|
||||
opus_val16 mid=0, side=0;
|
||||
unsigned cm=0;
|
||||
#ifdef RESYNTH
|
||||
int resynth = 1;
|
||||
#else
|
||||
int resynth = !ctx->encode;
|
||||
#endif
|
||||
int mbits, sbits, delta;
|
||||
int itheta;
|
||||
int qalloc;
|
||||
|
@ -1232,8 +1261,7 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
|
|||
|
||||
orig_fill = fill;
|
||||
|
||||
compute_theta(ctx, &sctx, X, Y, N, &b, B, B,
|
||||
LM, 1, &fill);
|
||||
compute_theta(ctx, &sctx, X, Y, N, &b, B, B, LM, 1, &fill);
|
||||
inv = sctx.inv;
|
||||
imid = sctx.imid;
|
||||
iside = sctx.iside;
|
||||
|
@ -1281,13 +1309,13 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
|
|||
sign = 1-2*sign;
|
||||
/* We use orig_fill here because we want to fold the side, but if
|
||||
itheta==16384, we'll have cleared the low bits of fill. */
|
||||
cm = quant_band(ctx, x2, N, mbits, B, lowband,
|
||||
LM, lowband_out, Q15ONE, lowband_scratch, orig_fill);
|
||||
cm = quant_band(ctx, x2, N, mbits, B, lowband, LM, lowband_out, Q15ONE,
|
||||
lowband_scratch, orig_fill);
|
||||
/* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
|
||||
and there's no need to worry about mixing with the other channel. */
|
||||
y2[0] = -sign*x2[1];
|
||||
y2[1] = sign*x2[0];
|
||||
if (resynth)
|
||||
if (ctx->resynth)
|
||||
{
|
||||
celt_norm tmp;
|
||||
X[0] = MULT16_16_Q15(mid, X[0]);
|
||||
|
@ -1314,38 +1342,32 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
|
|||
{
|
||||
/* In stereo mode, we do not apply a scaling to the mid because we need the normalized
|
||||
mid for folding later. */
|
||||
cm = quant_band(ctx, X, N, mbits, B,
|
||||
lowband, LM, lowband_out,
|
||||
Q15ONE, lowband_scratch, fill);
|
||||
cm = quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE,
|
||||
lowband_scratch, fill);
|
||||
rebalance = mbits - (rebalance-ctx->remaining_bits);
|
||||
if (rebalance > 3<<BITRES && itheta!=0)
|
||||
sbits += rebalance - (3<<BITRES);
|
||||
|
||||
/* For a stereo split, the high bits of fill are always zero, so no
|
||||
folding will be done to the side. */
|
||||
cm |= quant_band(ctx, Y, N, sbits, B,
|
||||
NULL, LM, NULL,
|
||||
side, NULL, fill>>B);
|
||||
cm |= quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B);
|
||||
} else {
|
||||
/* For a stereo split, the high bits of fill are always zero, so no
|
||||
folding will be done to the side. */
|
||||
cm = quant_band(ctx, Y, N, sbits, B,
|
||||
NULL, LM, NULL,
|
||||
side, NULL, fill>>B);
|
||||
cm = quant_band(ctx, Y, N, sbits, B, NULL, LM, NULL, side, NULL, fill>>B);
|
||||
rebalance = sbits - (rebalance-ctx->remaining_bits);
|
||||
if (rebalance > 3<<BITRES && itheta!=16384)
|
||||
mbits += rebalance - (3<<BITRES);
|
||||
/* In stereo mode, we do not apply a scaling to the mid because we need the normalized
|
||||
mid for folding later. */
|
||||
cm |= quant_band(ctx, X, N, mbits, B,
|
||||
lowband, LM, lowband_out,
|
||||
Q15ONE, lowband_scratch, fill);
|
||||
cm |= quant_band(ctx, X, N, mbits, B, lowband, LM, lowband_out, Q15ONE,
|
||||
lowband_scratch, fill);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* This code is used by the decoder and by the resynthesis-enabled encoder */
|
||||
if (resynth)
|
||||
if (ctx->resynth)
|
||||
{
|
||||
if (N!=2)
|
||||
stereo_merge(X, Y, mid, N, ctx->arch);
|
||||
|
@ -1359,19 +1381,38 @@ static unsigned quant_band_stereo(struct band_ctx *ctx, celt_norm *X, celt_norm
|
|||
return cm;
|
||||
}
|
||||
|
||||
static void special_hybrid_folding(const CELTMode *m, celt_norm *norm, celt_norm *norm2, int start, int M, int dual_stereo)
|
||||
{
|
||||
int n1, n2;
|
||||
const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
|
||||
n1 = M*(eBands[start+1]-eBands[start]);
|
||||
n2 = M*(eBands[start+2]-eBands[start+1]);
|
||||
/* Duplicate enough of the first band folding data to be able to fold the second band.
|
||||
Copies no data for CELT-only mode. */
|
||||
OPUS_COPY(&norm[n1], &norm[2*n1 - n2], n2-n1);
|
||||
if (dual_stereo)
|
||||
OPUS_COPY(&norm2[n1], &norm2[2*n1 - n2], n2-n1);
|
||||
}
|
||||
|
||||
void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
||||
celt_norm *X_, celt_norm *Y_, unsigned char *collapse_masks,
|
||||
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
|
||||
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
|
||||
opus_int32 balance, ec_ctx *ec, int LM, int codedBands,
|
||||
opus_uint32 *seed, int arch)
|
||||
opus_uint32 *seed, int complexity, int arch, int disable_inv)
|
||||
{
|
||||
int i;
|
||||
opus_int32 remaining_bits;
|
||||
const opus_int16 * OPUS_RESTRICT eBands = m->eBands;
|
||||
celt_norm * OPUS_RESTRICT norm, * OPUS_RESTRICT norm2;
|
||||
VARDECL(celt_norm, _norm);
|
||||
VARDECL(celt_norm, _lowband_scratch);
|
||||
VARDECL(celt_norm, X_save);
|
||||
VARDECL(celt_norm, Y_save);
|
||||
VARDECL(celt_norm, X_save2);
|
||||
VARDECL(celt_norm, Y_save2);
|
||||
VARDECL(celt_norm, norm_save2);
|
||||
int resynth_alloc;
|
||||
celt_norm *lowband_scratch;
|
||||
int B;
|
||||
int M;
|
||||
|
@ -1379,10 +1420,11 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
int update_lowband = 1;
|
||||
int C = Y_ != NULL ? 2 : 1;
|
||||
int norm_offset;
|
||||
int theta_rdo = encode && Y_!=NULL && !dual_stereo && complexity>=8;
|
||||
#ifdef RESYNTH
|
||||
int resynth = 1;
|
||||
#else
|
||||
int resynth = !encode;
|
||||
int resynth = !encode || theta_rdo;
|
||||
#endif
|
||||
struct band_ctx ctx;
|
||||
SAVE_STACK;
|
||||
|
@ -1395,9 +1437,24 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
ALLOC(_norm, C*(M*eBands[m->nbEBands-1]-norm_offset), celt_norm);
|
||||
norm = _norm;
|
||||
norm2 = norm + M*eBands[m->nbEBands-1]-norm_offset;
|
||||
/* We can use the last band as scratch space because we don't need that
|
||||
scratch space for the last band. */
|
||||
lowband_scratch = X_+M*eBands[m->nbEBands-1];
|
||||
|
||||
/* For decoding, we can use the last band as scratch space because we don't need that
|
||||
scratch space for the last band and we don't care about the data there until we're
|
||||
decoding the last band. */
|
||||
if (encode && resynth)
|
||||
resynth_alloc = M*(eBands[m->nbEBands]-eBands[m->nbEBands-1]);
|
||||
else
|
||||
resynth_alloc = ALLOC_NONE;
|
||||
ALLOC(_lowband_scratch, resynth_alloc, celt_norm);
|
||||
if (encode && resynth)
|
||||
lowband_scratch = _lowband_scratch;
|
||||
else
|
||||
lowband_scratch = X_+M*eBands[m->nbEBands-1];
|
||||
ALLOC(X_save, resynth_alloc, celt_norm);
|
||||
ALLOC(Y_save, resynth_alloc, celt_norm);
|
||||
ALLOC(X_save2, resynth_alloc, celt_norm);
|
||||
ALLOC(Y_save2, resynth_alloc, celt_norm);
|
||||
ALLOC(norm_save2, resynth_alloc, celt_norm);
|
||||
|
||||
lowband_offset = 0;
|
||||
ctx.bandE = bandE;
|
||||
|
@ -1408,6 +1465,11 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
ctx.seed = *seed;
|
||||
ctx.spread = spread;
|
||||
ctx.arch = arch;
|
||||
ctx.disable_inv = disable_inv;
|
||||
ctx.resynth = resynth;
|
||||
ctx.theta_round = 0;
|
||||
/* Avoid injecting noise in the first band on transients. */
|
||||
ctx.avoid_split_noise = B > 1;
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
opus_int32 tell;
|
||||
|
@ -1430,6 +1492,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
else
|
||||
Y = NULL;
|
||||
N = M*eBands[i+1]-M*eBands[i];
|
||||
celt_assert(N > 0);
|
||||
tell = ec_tell_frac(ec);
|
||||
|
||||
/* Compute how many bits we want to allocate to this band */
|
||||
|
@ -1445,8 +1508,15 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
b = 0;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_UPDATE_DRAFT
|
||||
if (resynth && (M*eBands[i]-N >= M*eBands[start] || i==start+1) && (update_lowband || lowband_offset==0))
|
||||
lowband_offset = i;
|
||||
if (i == start+1)
|
||||
special_hybrid_folding(m, norm, norm2, start, M, dual_stereo);
|
||||
#else
|
||||
if (resynth && M*eBands[i]-N >= M*eBands[start] && (update_lowband || lowband_offset==0))
|
||||
lowband_offset = i;
|
||||
#endif
|
||||
|
||||
tf_change = tf_res[i];
|
||||
ctx.tf_change = tf_change;
|
||||
|
@ -1457,7 +1527,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
Y = norm;
|
||||
lowband_scratch = NULL;
|
||||
}
|
||||
if (i==end-1)
|
||||
if (last && !theta_rdo)
|
||||
lowband_scratch = NULL;
|
||||
|
||||
/* Get a conservative estimate of the collapse_mask's for the bands we're
|
||||
|
@ -1472,7 +1542,11 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
fold_start = lowband_offset;
|
||||
while(M*eBands[--fold_start] > effective_lowband+norm_offset);
|
||||
fold_end = lowband_offset-1;
|
||||
#ifndef DISABLE_UPDATE_DRAFT
|
||||
while(++fold_end < i && M*eBands[fold_end] < effective_lowband+norm_offset+N);
|
||||
#else
|
||||
while(M*eBands[++fold_end] < effective_lowband+norm_offset+N);
|
||||
#endif
|
||||
x_cm = y_cm = 0;
|
||||
fold_i = fold_start; do {
|
||||
x_cm |= collapse_masks[fold_i*C+0];
|
||||
|
@ -1505,13 +1579,79 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
} else {
|
||||
if (Y!=NULL)
|
||||
{
|
||||
x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
|
||||
effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm);
|
||||
if (theta_rdo && i < intensity)
|
||||
{
|
||||
ec_ctx ec_save, ec_save2;
|
||||
struct band_ctx ctx_save, ctx_save2;
|
||||
opus_val32 dist0, dist1;
|
||||
unsigned cm, cm2;
|
||||
int nstart_bytes, nend_bytes, save_bytes;
|
||||
unsigned char *bytes_buf;
|
||||
unsigned char bytes_save[1275];
|
||||
opus_val16 w[2];
|
||||
compute_channel_weights(bandE[i], bandE[i+m->nbEBands], w);
|
||||
/* Make a copy. */
|
||||
cm = x_cm|y_cm;
|
||||
ec_save = *ec;
|
||||
ctx_save = ctx;
|
||||
OPUS_COPY(X_save, X, N);
|
||||
OPUS_COPY(Y_save, Y, N);
|
||||
/* Encode and round down. */
|
||||
ctx.theta_round = -1;
|
||||
x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
|
||||
effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm);
|
||||
dist0 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch));
|
||||
|
||||
/* Save first result. */
|
||||
cm2 = x_cm;
|
||||
ec_save2 = *ec;
|
||||
ctx_save2 = ctx;
|
||||
OPUS_COPY(X_save2, X, N);
|
||||
OPUS_COPY(Y_save2, Y, N);
|
||||
if (!last)
|
||||
OPUS_COPY(norm_save2, norm+M*eBands[i]-norm_offset, N);
|
||||
nstart_bytes = ec_save.offs;
|
||||
nend_bytes = ec_save.storage;
|
||||
bytes_buf = ec_save.buf+nstart_bytes;
|
||||
save_bytes = nend_bytes-nstart_bytes;
|
||||
OPUS_COPY(bytes_save, bytes_buf, save_bytes);
|
||||
|
||||
/* Restore */
|
||||
*ec = ec_save;
|
||||
ctx = ctx_save;
|
||||
OPUS_COPY(X, X_save, N);
|
||||
OPUS_COPY(Y, Y_save, N);
|
||||
#ifndef DISABLE_UPDATE_DRAFT
|
||||
if (i == start+1)
|
||||
special_hybrid_folding(m, norm, norm2, start, M, dual_stereo);
|
||||
#endif
|
||||
/* Encode and round up. */
|
||||
ctx.theta_round = 1;
|
||||
x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
|
||||
effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, cm);
|
||||
dist1 = MULT16_32_Q15(w[0], celt_inner_prod(X_save, X, N, arch)) + MULT16_32_Q15(w[1], celt_inner_prod(Y_save, Y, N, arch));
|
||||
if (dist0 >= dist1) {
|
||||
x_cm = cm2;
|
||||
*ec = ec_save2;
|
||||
ctx = ctx_save2;
|
||||
OPUS_COPY(X, X_save2, N);
|
||||
OPUS_COPY(Y, Y_save2, N);
|
||||
if (!last)
|
||||
OPUS_COPY(norm+M*eBands[i]-norm_offset, norm_save2, N);
|
||||
OPUS_COPY(bytes_buf, bytes_save, save_bytes);
|
||||
}
|
||||
} else {
|
||||
ctx.theta_round = 0;
|
||||
x_cm = quant_band_stereo(&ctx, X, Y, N, b, B,
|
||||
effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, lowband_scratch, x_cm|y_cm);
|
||||
}
|
||||
} else {
|
||||
x_cm = quant_band(&ctx, X, N, b, B,
|
||||
effective_lowband != -1 ? norm+effective_lowband : NULL, LM,
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm);
|
||||
last?NULL:norm+M*eBands[i]-norm_offset, Q15ONE, lowband_scratch, x_cm|y_cm);
|
||||
}
|
||||
y_cm = x_cm;
|
||||
}
|
||||
|
@ -1521,6 +1661,9 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
|
||||
/* Update the folding position only as long as we have 1 bit/sample depth. */
|
||||
update_lowband = b>(N<<BITRES);
|
||||
/* We only need to avoid noise on a split for the first band. After that, we
|
||||
have folding. */
|
||||
ctx.avoid_split_noise = 0;
|
||||
}
|
||||
*seed = ctx.seed;
|
||||
|
||||
|
|
|
@ -36,12 +36,15 @@
|
|||
#include "entdec.h"
|
||||
#include "rate.h"
|
||||
|
||||
opus_int16 bitexact_cos(opus_int16 x);
|
||||
int bitexact_log2tan(int isin,int icos);
|
||||
|
||||
/** Compute the amplitude (sqrt energy) in each of the bands
|
||||
* @param m Mode data
|
||||
* @param X Spectrum
|
||||
* @param bandE Square root of the energy for each band (returned)
|
||||
*/
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM);
|
||||
void compute_band_energies(const CELTMode *m, const celt_sig *X, celt_ener *bandE, int end, int C, int LM, int arch);
|
||||
|
||||
/*void compute_noise_energies(const CELTMode *m, const celt_sig *X, const opus_val16 *tonality, celt_ener *bandE);*/
|
||||
|
||||
|
@ -69,7 +72,7 @@ void denormalise_bands(const CELTMode *m, const celt_norm * OPUS_RESTRICT X,
|
|||
|
||||
int spreading_decision(const CELTMode *m, const celt_norm *X, int *average,
|
||||
int last_decision, int *hf_average, int *tapset_decision, int update_hf,
|
||||
int end, int C, int M);
|
||||
int end, int C, int M, const int *spread_weight);
|
||||
|
||||
#ifdef MEASURE_NORM_MSE
|
||||
void measure_norm_mse(const CELTMode *m, float *X, float *X0, float *bandE, float *bandE0, int M, int N, int C);
|
||||
|
@ -105,7 +108,7 @@ void quant_all_bands(int encode, const CELTMode *m, int start, int end,
|
|||
const celt_ener *bandE, int *pulses, int shortBlocks, int spread,
|
||||
int dual_stereo, int intensity, int *tf_res, opus_int32 total_bits,
|
||||
opus_int32 balance, ec_ctx *ec, int M, int codedBands, opus_uint32 *seed,
|
||||
int arch);
|
||||
int complexity, int arch, int disable_inv);
|
||||
|
||||
void anti_collapse(const CELTMode *m, celt_norm *X_,
|
||||
unsigned char *collapse_masks, int LM, int C, int size, int start,
|
||||
|
|
|
@ -111,26 +111,31 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
|
|||
t = MAC16_32_Q16(x[i], g10, x2);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i] = t;
|
||||
x4=SHL32(x[i-T+3],1);
|
||||
t = MAC16_32_Q16(x[i+1], g10, x1);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x0,x2));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x4,x3));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i+1] = t;
|
||||
x3=SHL32(x[i-T+4],1);
|
||||
t = MAC16_32_Q16(x[i+2], g10, x0);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x4,x1));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x3,x2));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i+2] = t;
|
||||
x2=SHL32(x[i-T+5],1);
|
||||
t = MAC16_32_Q16(x[i+3], g10, x4);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x3,x0));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x2,x1));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i+3] = t;
|
||||
x1=SHL32(x[i-T+6],1);
|
||||
t = MAC16_32_Q16(x[i+4], g10, x3);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x2,x4));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x1,x0));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i+4] = t;
|
||||
}
|
||||
#ifdef CUSTOM_MODES
|
||||
|
@ -141,6 +146,7 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
|
|||
t = MAC16_32_Q16(x[i], g10, x2);
|
||||
t = MAC16_32_Q16(t, g11, ADD32(x1,x3));
|
||||
t = MAC16_32_Q16(t, g12, ADD32(x0,x4));
|
||||
t = SATURATE(t, SIG_SAT);
|
||||
y[i] = t;
|
||||
x4=x3;
|
||||
x3=x2;
|
||||
|
@ -169,6 +175,7 @@ void comb_filter_const_c(opus_val32 *y, opus_val32 *x, int T, int N,
|
|||
+ MULT16_32_Q15(g10,x2)
|
||||
+ MULT16_32_Q15(g11,ADD32(x1,x3))
|
||||
+ MULT16_32_Q15(g12,ADD32(x0,x4));
|
||||
y[i] = SATURATE(y[i], SIG_SAT);
|
||||
x4=x3;
|
||||
x3=x2;
|
||||
x2=x1;
|
||||
|
@ -200,6 +207,10 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
|||
OPUS_MOVE(y, x, N);
|
||||
return;
|
||||
}
|
||||
/* When the gain is zero, T0 and/or T1 is set to zero. We need
|
||||
to have then be at least 2 to avoid processing garbage data. */
|
||||
T0 = IMAX(T0, COMBFILTER_MINPERIOD);
|
||||
T1 = IMAX(T1, COMBFILTER_MINPERIOD);
|
||||
g00 = MULT16_16_P15(g0, gains[tapset0][0]);
|
||||
g01 = MULT16_16_P15(g0, gains[tapset0][1]);
|
||||
g02 = MULT16_16_P15(g0, gains[tapset0][2]);
|
||||
|
@ -225,6 +236,7 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
|||
+ MULT16_32_Q15(MULT16_16_Q15(f,g10),x2)
|
||||
+ MULT16_32_Q15(MULT16_16_Q15(f,g11),ADD32(x1,x3))
|
||||
+ MULT16_32_Q15(MULT16_16_Q15(f,g12),ADD32(x0,x4));
|
||||
y[i] = SATURATE(y[i], SIG_SAT);
|
||||
x4=x3;
|
||||
x3=x2;
|
||||
x2=x1;
|
||||
|
@ -244,11 +256,16 @@ void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
|||
}
|
||||
#endif /* OVERRIDE_comb_filter */
|
||||
|
||||
/* TF change table. Positive values mean better frequency resolution (longer
|
||||
effective window), whereas negative values mean better time resolution
|
||||
(shorter effective window). The second index is computed as:
|
||||
4*isTransient + 2*tf_select + per_band_flag */
|
||||
const signed char tf_select_table[4][8] = {
|
||||
{0, -1, 0, -1, 0,-1, 0,-1},
|
||||
{0, -1, 0, -2, 1, 0, 1,-1},
|
||||
{0, -2, 0, -3, 2, 0, 1,-1},
|
||||
{0, -2, 0, -3, 3, 0, 1,-1},
|
||||
/*isTransient=0 isTransient=1 */
|
||||
{0, -1, 0, -1, 0,-1, 0,-1}, /* 2.5 ms */
|
||||
{0, -1, 0, -2, 1, 0, 1,-1}, /* 5 ms */
|
||||
{0, -2, 0, -3, 2, 0, 1,-1}, /* 10 ms */
|
||||
{0, -2, 0, -3, 3, 0, 1,-1}, /* 20 ms */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -50,6 +50,8 @@ extern "C" {
|
|||
#define CELTDecoder OpusCustomDecoder
|
||||
#define CELTMode OpusCustomMode
|
||||
|
||||
#define LEAK_BANDS 19
|
||||
|
||||
typedef struct {
|
||||
int valid;
|
||||
float tonality;
|
||||
|
@ -57,17 +59,27 @@ typedef struct {
|
|||
float noisiness;
|
||||
float activity;
|
||||
float music_prob;
|
||||
int bandwidth;
|
||||
}AnalysisInfo;
|
||||
float music_prob_min;
|
||||
float music_prob_max;
|
||||
int bandwidth;
|
||||
float activity_probability;
|
||||
float max_pitch_ratio;
|
||||
/* Store as Q6 char to save space. */
|
||||
unsigned char leak_boost[LEAK_BANDS];
|
||||
} AnalysisInfo;
|
||||
|
||||
typedef struct {
|
||||
int signalType;
|
||||
int offset;
|
||||
} SILKInfo;
|
||||
|
||||
#define __celt_check_mode_ptr_ptr(ptr) ((ptr) + ((ptr) - (const CELTMode**)(ptr)))
|
||||
|
||||
#define __celt_check_analysis_ptr(ptr) ((ptr) + ((ptr) - (const AnalysisInfo*)(ptr)))
|
||||
|
||||
/* Encoder/decoder Requests */
|
||||
#define __celt_check_silkinfo_ptr(ptr) ((ptr) + ((ptr) - (const SILKInfo*)(ptr)))
|
||||
|
||||
/* Expose this option again when variable framesize actually works */
|
||||
#define OPUS_FRAMESIZE_VARIABLE 5010 /**< Optimize the frame size dynamically */
|
||||
/* Encoder/decoder Requests */
|
||||
|
||||
|
||||
#define CELT_SET_PREDICTION_REQUEST 10002
|
||||
|
@ -116,6 +128,9 @@ typedef struct {
|
|||
#define OPUS_SET_ENERGY_MASK_REQUEST 10026
|
||||
#define OPUS_SET_ENERGY_MASK(x) OPUS_SET_ENERGY_MASK_REQUEST, __opus_check_val16_ptr(x)
|
||||
|
||||
#define CELT_SET_SILK_INFO_REQUEST 10028
|
||||
#define CELT_SET_SILK_INFO(x) CELT_SET_SILK_INFO_REQUEST, __celt_check_silkinfo_ptr(x)
|
||||
|
||||
/* Encoder stuff */
|
||||
|
||||
int celt_encoder_get_size(int channels);
|
||||
|
@ -194,6 +209,13 @@ static OPUS_INLINE int fromOpus(unsigned char c)
|
|||
|
||||
extern const signed char tf_select_table[4][8];
|
||||
|
||||
#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS)
|
||||
void validate_celt_decoder(CELTDecoder *st);
|
||||
#define VALIDATE_CELT_DECODER(st) validate_celt_decoder(st)
|
||||
#else
|
||||
#define VALIDATE_CELT_DECODER(st)
|
||||
#endif
|
||||
|
||||
int resampling_factor(opus_int32 rate);
|
||||
|
||||
void celt_preemphasis(const opus_val16 * OPUS_RESTRICT pcmp, celt_sig * OPUS_RESTRICT inp,
|
||||
|
|
|
@ -51,6 +51,14 @@
|
|||
#include "celt_lpc.h"
|
||||
#include "vq.h"
|
||||
|
||||
/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
|
||||
CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
|
||||
current value corresponds to a pitch of 66.67 Hz. */
|
||||
#define PLC_PITCH_LAG_MAX (720)
|
||||
/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
|
||||
pitch of 480 Hz. */
|
||||
#define PLC_PITCH_LAG_MIN (100)
|
||||
|
||||
#if defined(SMALL_FOOTPRINT) && defined(FIXED_POINT)
|
||||
#define NORM_ALIASING_HACK
|
||||
#endif
|
||||
|
@ -73,6 +81,7 @@ struct OpusCustomDecoder {
|
|||
int downsample;
|
||||
int start, end;
|
||||
int signalling;
|
||||
int disable_inv;
|
||||
int arch;
|
||||
|
||||
/* Everything beyond this point gets cleared on a reset */
|
||||
|
@ -100,6 +109,38 @@ struct OpusCustomDecoder {
|
|||
/* opus_val16 backgroundLogE[], Size = 2*mode->nbEBands */
|
||||
};
|
||||
|
||||
#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS)
|
||||
/* Make basic checks on the CELT state to ensure we don't end
|
||||
up writing all over memory. */
|
||||
void validate_celt_decoder(CELTDecoder *st)
|
||||
{
|
||||
#ifndef CUSTOM_MODES
|
||||
celt_assert(st->mode == opus_custom_mode_create(48000, 960, NULL));
|
||||
celt_assert(st->overlap == 120);
|
||||
#endif
|
||||
celt_assert(st->channels == 1 || st->channels == 2);
|
||||
celt_assert(st->stream_channels == 1 || st->stream_channels == 2);
|
||||
celt_assert(st->downsample > 0);
|
||||
celt_assert(st->start == 0 || st->start == 17);
|
||||
celt_assert(st->start < st->end);
|
||||
celt_assert(st->end <= 21);
|
||||
#ifdef OPUS_ARCHMASK
|
||||
celt_assert(st->arch >= 0);
|
||||
celt_assert(st->arch <= OPUS_ARCHMASK);
|
||||
#endif
|
||||
celt_assert(st->last_pitch_index <= PLC_PITCH_LAG_MAX);
|
||||
celt_assert(st->last_pitch_index >= PLC_PITCH_LAG_MIN || st->last_pitch_index == 0);
|
||||
celt_assert(st->postfilter_period < MAX_PERIOD);
|
||||
celt_assert(st->postfilter_period >= COMBFILTER_MINPERIOD || st->postfilter_period == 0);
|
||||
celt_assert(st->postfilter_period_old < MAX_PERIOD);
|
||||
celt_assert(st->postfilter_period_old >= COMBFILTER_MINPERIOD || st->postfilter_period_old == 0);
|
||||
celt_assert(st->postfilter_tapset <= 2);
|
||||
celt_assert(st->postfilter_tapset >= 0);
|
||||
celt_assert(st->postfilter_tapset_old <= 2);
|
||||
celt_assert(st->postfilter_tapset_old >= 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
int celt_decoder_get_size(int channels)
|
||||
{
|
||||
const CELTMode *mode = opus_custom_mode_create(48000, 960, NULL);
|
||||
|
@ -163,6 +204,11 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_decoder_init(CELTDecoder *st, const CELTMod
|
|||
st->start = 0;
|
||||
st->end = st->mode->effEBands;
|
||||
st->signalling = 1;
|
||||
#ifndef DISABLE_UPDATE_DRAFT
|
||||
st->disable_inv = channels == 1;
|
||||
#else
|
||||
st->disable_inv = 0;
|
||||
#endif
|
||||
st->arch = opus_select_arch();
|
||||
|
||||
opus_custom_decoder_ctl(st, OPUS_RESET_STATE);
|
||||
|
@ -177,6 +223,36 @@ void opus_custom_decoder_destroy(CELTDecoder *st)
|
|||
}
|
||||
#endif /* CUSTOM_MODES */
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
/* Special case for stereo with no downsampling and no accumulation. This is
|
||||
quite common and we can make it faster by processing both channels in the
|
||||
same loop, reducing overhead due to the dependency loop in the IIR filter. */
|
||||
static void deemphasis_stereo_simple(celt_sig *in[], opus_val16 *pcm, int N, const opus_val16 coef0,
|
||||
celt_sig *mem)
|
||||
{
|
||||
celt_sig * OPUS_RESTRICT x0;
|
||||
celt_sig * OPUS_RESTRICT x1;
|
||||
celt_sig m0, m1;
|
||||
int j;
|
||||
x0=in[0];
|
||||
x1=in[1];
|
||||
m0 = mem[0];
|
||||
m1 = mem[1];
|
||||
for (j=0;j<N;j++)
|
||||
{
|
||||
celt_sig tmp0, tmp1;
|
||||
/* Add VERY_SMALL to x[] first to reduce dependency chain. */
|
||||
tmp0 = x0[j] + VERY_SMALL + m0;
|
||||
tmp1 = x1[j] + VERY_SMALL + m1;
|
||||
m0 = MULT16_32_Q15(coef0, tmp0);
|
||||
m1 = MULT16_32_Q15(coef0, tmp1);
|
||||
pcm[2*j ] = SCALEOUT(SIG2WORD16(tmp0));
|
||||
pcm[2*j+1] = SCALEOUT(SIG2WORD16(tmp1));
|
||||
}
|
||||
mem[0] = m0;
|
||||
mem[1] = m1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RESYNTH
|
||||
static
|
||||
|
@ -190,6 +266,14 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
|||
opus_val16 coef0;
|
||||
VARDECL(celt_sig, scratch);
|
||||
SAVE_STACK;
|
||||
#ifndef CUSTOM_MODES
|
||||
/* Short version for common case. */
|
||||
if (downsample == 1 && C == 2 && !accum)
|
||||
{
|
||||
deemphasis_stereo_simple(in, pcm, N, coef[0], mem);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#ifndef FIXED_POINT
|
||||
(void)accum;
|
||||
celt_assert(accum==0);
|
||||
|
@ -225,7 +309,7 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
|||
/* Shortcut for the standard (non-custom modes) case */
|
||||
for (j=0;j<N;j++)
|
||||
{
|
||||
celt_sig tmp = x[j] + m + VERY_SMALL;
|
||||
celt_sig tmp = x[j] + VERY_SMALL + m;
|
||||
m = MULT16_32_Q15(coef0, tmp);
|
||||
scratch[j] = tmp;
|
||||
}
|
||||
|
@ -246,7 +330,7 @@ void deemphasis(celt_sig *in[], opus_val16 *pcm, int N, int C, int downsample, c
|
|||
{
|
||||
for (j=0;j<N;j++)
|
||||
{
|
||||
celt_sig tmp = x[j] + m + VERY_SMALL;
|
||||
celt_sig tmp = x[j] + VERY_SMALL + m;
|
||||
m = MULT16_32_Q15(coef0, tmp);
|
||||
y[j*C] = SCALEOUT(SIG2WORD16(tmp));
|
||||
}
|
||||
|
@ -333,7 +417,7 @@ void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
|
|||
denormalise_bands(mode, X+N, freq2, oldBandE+nbEBands, start, effEnd, M,
|
||||
downsample, silence);
|
||||
for (i=0;i<N;i++)
|
||||
freq[i] = HALF32(ADD32(freq[i],freq2[i]));
|
||||
freq[i] = ADD32(HALF32(freq[i]), HALF32(freq2[i]));
|
||||
for (b=0;b<B;b++)
|
||||
clt_mdct_backward(&mode->mdct, &freq[b], out_syn[0]+NB*b, mode->window, overlap, shift, B, arch);
|
||||
} else {
|
||||
|
@ -345,6 +429,12 @@ void celt_synthesis(const CELTMode *mode, celt_norm *X, celt_sig * out_syn[],
|
|||
clt_mdct_backward(&mode->mdct, &freq[b], out_syn[c]+NB*b, mode->window, overlap, shift, B, arch);
|
||||
} while (++c<CC);
|
||||
}
|
||||
/* Saturate IMDCT output so that we can't overflow in the pitch postfilter
|
||||
or in the */
|
||||
c=0; do {
|
||||
for (i=0;i<N;i++)
|
||||
out_syn[c][i] = SATURATE(out_syn[c][i], SIG_SAT);
|
||||
} while (++c<CC);
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
|
@ -387,14 +477,6 @@ static void tf_decode(int start, int end, int isTransient, int *tf_res, int LM,
|
|||
}
|
||||
}
|
||||
|
||||
/* The maximum pitch lag to allow in the pitch-based PLC. It's possible to save
|
||||
CPU time in the PLC pitch search by making this smaller than MAX_PERIOD. The
|
||||
current value corresponds to a pitch of 66.67 Hz. */
|
||||
#define PLC_PITCH_LAG_MAX (720)
|
||||
/* The minimum pitch lag to allow in the pitch-based PLC. This corresponds to a
|
||||
pitch of 480 Hz. */
|
||||
#define PLC_PITCH_LAG_MIN (100)
|
||||
|
||||
static int celt_plc_pitch_search(celt_sig *decode_mem[2], int C, int arch)
|
||||
{
|
||||
int pitch_index;
|
||||
|
@ -504,12 +586,15 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
|
||||
celt_synthesis(mode, X, out_syn, oldBandE, start, effEnd, C, C, 0, LM, st->downsample, 0, st->arch);
|
||||
} else {
|
||||
int exc_length;
|
||||
/* Pitch-based PLC */
|
||||
const opus_val16 *window;
|
||||
opus_val16 *exc;
|
||||
opus_val16 fade = Q15ONE;
|
||||
int pitch_index;
|
||||
VARDECL(opus_val32, etmp);
|
||||
VARDECL(opus_val16, exc);
|
||||
VARDECL(opus_val16, _exc);
|
||||
VARDECL(opus_val16, fir_tmp);
|
||||
|
||||
if (loss_count == 0)
|
||||
{
|
||||
|
@ -519,8 +604,14 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
fade = QCONST16(.8f,15);
|
||||
}
|
||||
|
||||
/* We want the excitation for 2 pitch periods in order to look for a
|
||||
decaying signal, but we can't get more than MAX_PERIOD. */
|
||||
exc_length = IMIN(2*pitch_index, MAX_PERIOD);
|
||||
|
||||
ALLOC(etmp, overlap, opus_val32);
|
||||
ALLOC(exc, MAX_PERIOD, opus_val16);
|
||||
ALLOC(_exc, MAX_PERIOD+LPC_ORDER, opus_val16);
|
||||
ALLOC(fir_tmp, exc_length, opus_val16);
|
||||
exc = _exc+LPC_ORDER;
|
||||
window = mode->window;
|
||||
c=0; do {
|
||||
opus_val16 decay;
|
||||
|
@ -529,13 +620,11 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
celt_sig *buf;
|
||||
int extrapolation_offset;
|
||||
int extrapolation_len;
|
||||
int exc_length;
|
||||
int j;
|
||||
|
||||
buf = decode_mem[c];
|
||||
for (i=0;i<MAX_PERIOD;i++) {
|
||||
exc[i] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD+i], SIG_SHIFT);
|
||||
}
|
||||
for (i=0;i<MAX_PERIOD+LPC_ORDER;i++)
|
||||
exc[i-LPC_ORDER] = ROUND16(buf[DECODE_BUFFER_SIZE-MAX_PERIOD-LPC_ORDER+i], SIG_SHIFT);
|
||||
|
||||
if (loss_count == 0)
|
||||
{
|
||||
|
@ -561,22 +650,32 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
#endif
|
||||
}
|
||||
_celt_lpc(lpc+c*LPC_ORDER, ac, LPC_ORDER);
|
||||
#ifdef FIXED_POINT
|
||||
/* For fixed-point, apply bandwidth expansion until we can guarantee that
|
||||
no overflow can happen in the IIR filter. This means:
|
||||
32768*sum(abs(filter)) < 2^31 */
|
||||
while (1) {
|
||||
opus_val16 tmp=Q15ONE;
|
||||
opus_val32 sum=QCONST16(1., SIG_SHIFT);
|
||||
for (i=0;i<LPC_ORDER;i++)
|
||||
sum += ABS16(lpc[c*LPC_ORDER+i]);
|
||||
if (sum < 65535) break;
|
||||
for (i=0;i<LPC_ORDER;i++)
|
||||
{
|
||||
tmp = MULT16_16_Q15(QCONST16(.99f,15), tmp);
|
||||
lpc[c*LPC_ORDER+i] = MULT16_16_Q15(lpc[c*LPC_ORDER+i], tmp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
/* We want the excitation for 2 pitch periods in order to look for a
|
||||
decaying signal, but we can't get more than MAX_PERIOD. */
|
||||
exc_length = IMIN(2*pitch_index, MAX_PERIOD);
|
||||
/* Initialize the LPC history with the samples just before the start
|
||||
of the region for which we're computing the excitation. */
|
||||
{
|
||||
opus_val16 lpc_mem[LPC_ORDER];
|
||||
for (i=0;i<LPC_ORDER;i++)
|
||||
{
|
||||
lpc_mem[i] =
|
||||
ROUND16(buf[DECODE_BUFFER_SIZE-exc_length-1-i], SIG_SHIFT);
|
||||
}
|
||||
/* Compute the excitation for exc_length samples before the loss. */
|
||||
/* Compute the excitation for exc_length samples before the loss. We need the copy
|
||||
because celt_fir() cannot filter in-place. */
|
||||
celt_fir(exc+MAX_PERIOD-exc_length, lpc+c*LPC_ORDER,
|
||||
exc+MAX_PERIOD-exc_length, exc_length, LPC_ORDER, lpc_mem, st->arch);
|
||||
fir_tmp, exc_length, LPC_ORDER, st->arch);
|
||||
OPUS_COPY(exc+MAX_PERIOD-exc_length, fir_tmp, exc_length);
|
||||
}
|
||||
|
||||
/* Check if the waveform is decaying, and if so how fast.
|
||||
|
@ -630,9 +729,8 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
tmp = ROUND16(
|
||||
buf[DECODE_BUFFER_SIZE-MAX_PERIOD-N+extrapolation_offset+j],
|
||||
SIG_SHIFT);
|
||||
S1 += SHR32(MULT16_16(tmp, tmp), 8);
|
||||
S1 += SHR32(MULT16_16(tmp, tmp), 10);
|
||||
}
|
||||
|
||||
{
|
||||
opus_val16 lpc_mem[LPC_ORDER];
|
||||
/* Copy the last decoded samples (prior to the overlap region) to
|
||||
|
@ -644,6 +742,10 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
celt_iir(buf+DECODE_BUFFER_SIZE-N, lpc+c*LPC_ORDER,
|
||||
buf+DECODE_BUFFER_SIZE-N, extrapolation_len, LPC_ORDER,
|
||||
lpc_mem, st->arch);
|
||||
#ifdef FIXED_POINT
|
||||
for (i=0; i < extrapolation_len; i++)
|
||||
buf[DECODE_BUFFER_SIZE-N+i] = SATURATE(buf[DECODE_BUFFER_SIZE-N+i], SIG_SAT);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if the synthesis energy is higher than expected, which can
|
||||
|
@ -654,7 +756,7 @@ static void celt_decode_lost(CELTDecoder * OPUS_RESTRICT st, int N, int LM)
|
|||
for (i=0;i<extrapolation_len;i++)
|
||||
{
|
||||
opus_val16 tmp = ROUND16(buf[DECODE_BUFFER_SIZE-N+i], SIG_SHIFT);
|
||||
S2 += SHR32(MULT16_16(tmp, tmp), 8);
|
||||
S2 += SHR32(MULT16_16(tmp, tmp), 10);
|
||||
}
|
||||
/* This checks for an "explosion" in the synthesis. */
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -762,6 +864,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
|||
const opus_int16 *eBands;
|
||||
ALLOC_STACK;
|
||||
|
||||
VALIDATE_CELT_DECODER(st);
|
||||
mode = st->mode;
|
||||
nbEBands = mode->nbEBands;
|
||||
overlap = mode->overlap;
|
||||
|
@ -956,7 +1059,7 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
|||
ALLOC(pulses, nbEBands, int);
|
||||
ALLOC(fine_priority, nbEBands, int);
|
||||
|
||||
codedBands = compute_allocation(mode, start, end, offsets, cap,
|
||||
codedBands = clt_compute_allocation(mode, start, end, offsets, cap,
|
||||
alloc_trim, &intensity, &dual_stereo, bits, &balance, pulses,
|
||||
fine_quant, fine_priority, C, LM, dec, 0, 0, 0);
|
||||
|
||||
|
@ -979,7 +1082,8 @@ int celt_decode_with_ec(CELTDecoder * OPUS_RESTRICT st, const unsigned char *dat
|
|||
|
||||
quant_all_bands(0, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
|
||||
NULL, pulses, shortBlocks, spread_decision, dual_stereo, intensity, tf_res,
|
||||
len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, st->arch);
|
||||
len*(8<<BITRES)-anti_collapse_rsv, balance, dec, LM, codedBands, &st->rng, 0,
|
||||
st->arch, st->disable_inv);
|
||||
|
||||
if (anti_collapse_rsv > 0)
|
||||
{
|
||||
|
@ -1234,6 +1338,26 @@ int opus_custom_decoder_ctl(CELTDecoder * OPUS_RESTRICT st, int request, ...)
|
|||
*value=st->rng;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 value = va_arg(ap, opus_int32);
|
||||
if(value<0 || value>1)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
st->disable_inv = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->disable_inv;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto bad_request;
|
||||
}
|
||||
|
|
|
@ -73,8 +73,8 @@ struct OpusCustomEncoder {
|
|||
int constrained_vbr; /* If zero, VBR can do whatever it likes with the rate */
|
||||
int loss_rate;
|
||||
int lsb_depth;
|
||||
int variable_duration;
|
||||
int lfe;
|
||||
int disable_inv;
|
||||
int arch;
|
||||
|
||||
/* Everything beyond this point gets cleared on a reset */
|
||||
|
@ -98,6 +98,7 @@ struct OpusCustomEncoder {
|
|||
#endif
|
||||
int consec_transient;
|
||||
AnalysisInfo analysis;
|
||||
SILKInfo silk_info;
|
||||
|
||||
opus_val32 preemph_memE[2];
|
||||
opus_val32 preemph_memD[2];
|
||||
|
@ -123,6 +124,7 @@ struct OpusCustomEncoder {
|
|||
/* opus_val16 oldBandE[], Size = channels*mode->nbEBands */
|
||||
/* opus_val16 oldLogE[], Size = channels*mode->nbEBands */
|
||||
/* opus_val16 oldLogE2[], Size = channels*mode->nbEBands */
|
||||
/* opus_val16 energyError[], Size = channels*mode->nbEBands */
|
||||
};
|
||||
|
||||
int celt_encoder_get_size(int channels)
|
||||
|
@ -136,9 +138,10 @@ OPUS_CUSTOM_NOSTATIC int opus_custom_encoder_get_size(const CELTMode *mode, int
|
|||
int size = sizeof(struct CELTEncoder)
|
||||
+ (channels*mode->overlap-1)*sizeof(celt_sig) /* celt_sig in_mem[channels*mode->overlap]; */
|
||||
+ channels*COMBFILTER_MAXPERIOD*sizeof(celt_sig) /* celt_sig prefilter_mem[channels*COMBFILTER_MAXPERIOD]; */
|
||||
+ 3*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */
|
||||
+ 4*channels*mode->nbEBands*sizeof(opus_val16); /* opus_val16 oldBandE[channels*mode->nbEBands]; */
|
||||
/* opus_val16 oldLogE[channels*mode->nbEBands]; */
|
||||
/* opus_val16 oldLogE2[channels*mode->nbEBands]; */
|
||||
/* opus_val16 energyError[channels*mode->nbEBands]; */
|
||||
return size;
|
||||
}
|
||||
|
||||
|
@ -178,7 +181,6 @@ static int opus_custom_encoder_init_arch(CELTEncoder *st, const CELTMode *mode,
|
|||
st->start = 0;
|
||||
st->end = st->mode->effEBands;
|
||||
st->signalling = 1;
|
||||
|
||||
st->arch = arch;
|
||||
|
||||
st->constrained_vbr = 1;
|
||||
|
@ -223,7 +225,8 @@ void opus_custom_encoder_destroy(CELTEncoder *st)
|
|||
|
||||
|
||||
static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int C,
|
||||
opus_val16 *tf_estimate, int *tf_chan)
|
||||
opus_val16 *tf_estimate, int *tf_chan, int allow_weak_transients,
|
||||
int *weak_transient)
|
||||
{
|
||||
int i;
|
||||
VARDECL(opus_val16, tmp);
|
||||
|
@ -233,6 +236,12 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
int c;
|
||||
opus_val16 tf_max;
|
||||
int len2;
|
||||
/* Forward masking: 6.7 dB/ms. */
|
||||
#ifdef FIXED_POINT
|
||||
int forward_shift = 4;
|
||||
#else
|
||||
opus_val16 forward_decay = QCONST16(.0625f,15);
|
||||
#endif
|
||||
/* Table of 6*64/x, trained on real data to minimize the average error */
|
||||
static const unsigned char inv_table[128] = {
|
||||
255,255,156,110, 86, 70, 59, 51, 45, 40, 37, 33, 31, 28, 26, 25,
|
||||
|
@ -247,6 +256,19 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
SAVE_STACK;
|
||||
ALLOC(tmp, len, opus_val16);
|
||||
|
||||
*weak_transient = 0;
|
||||
/* For lower bitrates, let's be more conservative and have a forward masking
|
||||
decay of 3.3 dB/ms. This avoids having to code transients at very low
|
||||
bitrate (mostly for hybrid), which can result in unstable energy and/or
|
||||
partial collapse. */
|
||||
if (allow_weak_transients)
|
||||
{
|
||||
#ifdef FIXED_POINT
|
||||
forward_shift = 5;
|
||||
#else
|
||||
forward_decay = QCONST16(.03125f,15);
|
||||
#endif
|
||||
}
|
||||
len2=len/2;
|
||||
for (c=0;c<C;c++)
|
||||
{
|
||||
|
@ -269,7 +291,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
mem0 = mem1 + y - 2*x;
|
||||
mem1 = x - .5f*y;
|
||||
#endif
|
||||
tmp[i] = EXTRACT16(SHR32(y,2));
|
||||
tmp[i] = SROUND16(y, 2);
|
||||
/*printf("%f ", tmp[i]);*/
|
||||
}
|
||||
/*printf("\n");*/
|
||||
|
@ -280,7 +302,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
/* Normalize tmp to max range */
|
||||
{
|
||||
int shift=0;
|
||||
shift = 14-celt_ilog2(1+celt_maxabs16(tmp, len));
|
||||
shift = 14-celt_ilog2(MAX16(1, celt_maxabs16(tmp, len)));
|
||||
if (shift!=0)
|
||||
{
|
||||
for (i=0;i<len;i++)
|
||||
|
@ -299,9 +321,9 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
mean += x2;
|
||||
#ifdef FIXED_POINT
|
||||
/* FIXME: Use PSHR16() instead */
|
||||
tmp[i] = mem0 + PSHR32(x2-mem0,4);
|
||||
tmp[i] = mem0 + PSHR32(x2-mem0,forward_shift);
|
||||
#else
|
||||
tmp[i] = mem0 + MULT16_16_P15(QCONST16(.0625f,15),x2-mem0);
|
||||
tmp[i] = mem0 + MULT16_16_P15(forward_decay,x2-mem0);
|
||||
#endif
|
||||
mem0 = tmp[i];
|
||||
}
|
||||
|
@ -311,6 +333,7 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
/* Backward pass to compute the pre-echo threshold */
|
||||
for (i=len2-1;i>=0;i--)
|
||||
{
|
||||
/* Backward masking: 13.9 dB/ms. */
|
||||
#ifdef FIXED_POINT
|
||||
/* FIXME: Use PSHR16() instead */
|
||||
tmp[i] = mem0 + PSHR32(tmp[i]-mem0,3);
|
||||
|
@ -339,6 +362,12 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
/* Compute harmonic mean discarding the unreliable boundaries
|
||||
The data is smooth, so we only take 1/4th of the samples */
|
||||
unmask=0;
|
||||
/* We should never see NaNs here. If we find any, then something really bad happened and we better abort
|
||||
before it does any damage later on. If these asserts are disabled (no hardening), then the table
|
||||
lookup a few lines below (id = ...) is likely to crash dur to an out-of-bounds read. DO NOT FIX
|
||||
that crash on NaN since it could result in a worse issue later on. */
|
||||
celt_assert(!celt_isnan(tmp[0]));
|
||||
celt_assert(!celt_isnan(norm));
|
||||
for (i=12;i<len2-5;i+=4)
|
||||
{
|
||||
int id;
|
||||
|
@ -359,7 +388,12 @@ static int transient_analysis(const opus_val32 * OPUS_RESTRICT in, int len, int
|
|||
}
|
||||
}
|
||||
is_transient = mask_metric>200;
|
||||
|
||||
/* For low bitrates, define "weak transients" that need to be
|
||||
handled differently to avoid partial collapse. */
|
||||
if (allow_weak_transients && is_transient && mask_metric<600) {
|
||||
is_transient = 0;
|
||||
*weak_transient = 1;
|
||||
}
|
||||
/* Arbitrary metric for VBR boost */
|
||||
tf_max = MAX16(0,celt_sqrt(27*mask_metric)-42);
|
||||
/* *tf_estimate = 1 + MIN16(1, sqrt(MAX16(0, tf_max-30))/20); */
|
||||
|
@ -549,7 +583,7 @@ static opus_val32 l1_metric(const celt_norm *tmp, int N, int LM, opus_val16 bias
|
|||
|
||||
static int tf_analysis(const CELTMode *m, int len, int isTransient,
|
||||
int *tf_res, int lambda, celt_norm *X, int N0, int LM,
|
||||
int *tf_sum, opus_val16 tf_estimate, int tf_chan)
|
||||
opus_val16 tf_estimate, int tf_chan, int *importance)
|
||||
{
|
||||
int i;
|
||||
VARDECL(int, metric);
|
||||
|
@ -574,7 +608,6 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient,
|
|||
ALLOC(path0, len, int);
|
||||
ALLOC(path1, len, int);
|
||||
|
||||
*tf_sum = 0;
|
||||
for (i=0;i<len;i++)
|
||||
{
|
||||
int k, N;
|
||||
|
@ -629,27 +662,26 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient,
|
|||
metric[i] = 2*best_level;
|
||||
else
|
||||
metric[i] = -2*best_level;
|
||||
*tf_sum += (isTransient ? LM : 0) - metric[i]/2;
|
||||
/* For bands that can't be split to -1, set the metric to the half-way point to avoid
|
||||
biasing the decision */
|
||||
if (narrow && (metric[i]==0 || metric[i]==-2*LM))
|
||||
metric[i]-=1;
|
||||
/*printf("%d ", metric[i]);*/
|
||||
/*printf("%d ", metric[i]/2 + (!isTransient)*LM);*/
|
||||
}
|
||||
/*printf("\n");*/
|
||||
/* Search for the optimal tf resolution, including tf_select */
|
||||
tf_select = 0;
|
||||
for (sel=0;sel<2;sel++)
|
||||
{
|
||||
cost0 = 0;
|
||||
cost1 = isTransient ? 0 : lambda;
|
||||
cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
|
||||
cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*sel+1]) + (isTransient ? 0 : lambda);
|
||||
for (i=1;i<len;i++)
|
||||
{
|
||||
int curr0, curr1;
|
||||
curr0 = IMIN(cost0, cost1 + lambda);
|
||||
curr1 = IMIN(cost0 + lambda, cost1);
|
||||
cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
|
||||
cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
|
||||
cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+0]);
|
||||
cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*sel+1]);
|
||||
}
|
||||
cost0 = IMIN(cost0, cost1);
|
||||
selcost[sel]=cost0;
|
||||
|
@ -658,8 +690,8 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient,
|
|||
* If tests confirm it's useful for non-transients, we could allow it. */
|
||||
if (selcost[1]<selcost[0] && isTransient)
|
||||
tf_select=1;
|
||||
cost0 = 0;
|
||||
cost1 = isTransient ? 0 : lambda;
|
||||
cost0 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
|
||||
cost1 = importance[0]*abs(metric[0]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]) + (isTransient ? 0 : lambda);
|
||||
/* Viterbi forward pass */
|
||||
for (i=1;i<len;i++)
|
||||
{
|
||||
|
@ -687,8 +719,8 @@ static int tf_analysis(const CELTMode *m, int len, int isTransient,
|
|||
curr1 = from1;
|
||||
path1[i]= 1;
|
||||
}
|
||||
cost0 = curr0 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
|
||||
cost1 = curr1 + abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
|
||||
cost0 = curr0 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+0]);
|
||||
cost1 = curr1 + importance[i]*abs(metric[i]-2*tf_select_table[LM][4*isTransient+2*tf_select+1]);
|
||||
}
|
||||
tf_res[len-1] = cost0 < cost1 ? 0 : 1;
|
||||
/* Viterbi backward pass to check the decisions */
|
||||
|
@ -754,7 +786,7 @@ static void tf_encode(int start, int end, int isTransient, int *tf_res, int LM,
|
|||
static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
|
||||
const opus_val16 *bandLogE, int end, int LM, int C, int N0,
|
||||
AnalysisInfo *analysis, opus_val16 *stereo_saving, opus_val16 tf_estimate,
|
||||
int intensity, opus_val16 surround_trim, int arch)
|
||||
int intensity, opus_val16 surround_trim, opus_int32 equiv_rate, int arch)
|
||||
{
|
||||
int i;
|
||||
opus_val32 diff=0;
|
||||
|
@ -762,6 +794,14 @@ static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
|
|||
int trim_index;
|
||||
opus_val16 trim = QCONST16(5.f, 8);
|
||||
opus_val16 logXC, logXC2;
|
||||
/* At low bitrate, reducing the trim seems to help. At higher bitrates, it's less
|
||||
clear what's best, so we're keeping it as it was before, at least for now. */
|
||||
if (equiv_rate < 64000) {
|
||||
trim = QCONST16(4.f, 8);
|
||||
} else if (equiv_rate < 80000) {
|
||||
opus_int32 frac = (equiv_rate-64000) >> 10;
|
||||
trim = QCONST16(4.f, 8) + QCONST16(1.f/16.f, 8)*frac;
|
||||
}
|
||||
if (C==2)
|
||||
{
|
||||
opus_val16 sum = 0; /* Q10 */
|
||||
|
@ -809,7 +849,7 @@ static int alloc_trim_analysis(const CELTMode *m, const celt_norm *X,
|
|||
} while (++c<C);
|
||||
diff /= C*(end-1);
|
||||
/*printf("%f\n", diff);*/
|
||||
trim -= MAX16(-QCONST16(2.f, 8), MIN16(QCONST16(2.f, 8), SHR16(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 ));
|
||||
trim -= MAX32(-QCONST16(2.f, 8), MIN32(QCONST16(2.f, 8), SHR32(diff+QCONST16(1.f, DB_SHIFT),DB_SHIFT-8)/6 ));
|
||||
trim -= SHR16(surround_trim, DB_SHIFT-8);
|
||||
trim -= 2*SHR16(tf_estimate, 14-8);
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
|
@ -930,7 +970,8 @@ static opus_val16 median_of_3(const opus_val16 *x)
|
|||
static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16 *bandLogE2,
|
||||
int nbEBands, int start, int end, int C, int *offsets, int lsb_depth, const opus_int16 *logN,
|
||||
int isTransient, int vbr, int constrained_vbr, const opus_int16 *eBands, int LM,
|
||||
int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc)
|
||||
int effectiveBytes, opus_int32 *tot_boost_, int lfe, opus_val16 *surround_dynalloc,
|
||||
AnalysisInfo *analysis, int *importance, int *spread_weight)
|
||||
{
|
||||
int i, c;
|
||||
opus_int32 tot_boost=0;
|
||||
|
@ -956,6 +997,42 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
for (i=0;i<end;i++)
|
||||
maxDepth = MAX16(maxDepth, bandLogE[c*nbEBands+i]-noise_floor[i]);
|
||||
} while (++c<C);
|
||||
{
|
||||
/* Compute a really simple masking model to avoid taking into account completely masked
|
||||
bands when computing the spreading decision. */
|
||||
VARDECL(opus_val16, mask);
|
||||
VARDECL(opus_val16, sig);
|
||||
ALLOC(mask, nbEBands, opus_val16);
|
||||
ALLOC(sig, nbEBands, opus_val16);
|
||||
for (i=0;i<end;i++)
|
||||
mask[i] = bandLogE[i]-noise_floor[i];
|
||||
if (C==2)
|
||||
{
|
||||
for (i=0;i<end;i++)
|
||||
mask[i] = MAX16(mask[i], bandLogE[nbEBands+i]-noise_floor[i]);
|
||||
}
|
||||
OPUS_COPY(sig, mask, end);
|
||||
for (i=1;i<end;i++)
|
||||
mask[i] = MAX16(mask[i], mask[i-1] - QCONST16(2.f, DB_SHIFT));
|
||||
for (i=end-2;i>=0;i--)
|
||||
mask[i] = MAX16(mask[i], mask[i+1] - QCONST16(3.f, DB_SHIFT));
|
||||
for (i=0;i<end;i++)
|
||||
{
|
||||
/* Compute SMR: Mask is never more than 72 dB below the peak and never below the noise floor.*/
|
||||
opus_val16 smr = sig[i]-MAX16(MAX16(0, maxDepth-QCONST16(12.f, DB_SHIFT)), mask[i]);
|
||||
/* Clamp SMR to make sure we're not shifting by something negative or too large. */
|
||||
#ifdef FIXED_POINT
|
||||
/* FIXME: Use PSHR16() instead */
|
||||
int shift = -PSHR32(MAX16(-QCONST16(5.f, DB_SHIFT), MIN16(0, smr)), DB_SHIFT);
|
||||
#else
|
||||
int shift = IMIN(5, IMAX(0, -(int)floor(.5f + smr)));
|
||||
#endif
|
||||
spread_weight[i] = 32 >> shift;
|
||||
}
|
||||
/*for (i=0;i<end;i++)
|
||||
printf("%d ", spread_weight[i]);
|
||||
printf("\n");*/
|
||||
}
|
||||
/* Make sure that dynamic allocation can't make us bust the budget */
|
||||
if (effectiveBytes > 50 && LM>=1 && !lfe)
|
||||
{
|
||||
|
@ -1012,6 +1089,14 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
}
|
||||
for (i=start;i<end;i++)
|
||||
follower[i] = MAX16(follower[i], surround_dynalloc[i]);
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
#ifdef FIXED_POINT
|
||||
importance[i] = PSHR32(13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT))), 16);
|
||||
#else
|
||||
importance[i] = (int)floor(.5f+13*celt_exp2(MIN16(follower[i], QCONST16(4.f, DB_SHIFT))));
|
||||
#endif
|
||||
}
|
||||
/* For non-transient CBR/CVBR frames, halve the dynalloc contribution */
|
||||
if ((!vbr || constrained_vbr)&&!isTransient)
|
||||
{
|
||||
|
@ -1020,14 +1105,26 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
}
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
int width;
|
||||
int boost;
|
||||
int boost_bits;
|
||||
|
||||
if (i<8)
|
||||
follower[i] *= 2;
|
||||
if (i>=12)
|
||||
follower[i] = HALF16(follower[i]);
|
||||
}
|
||||
#ifdef DISABLE_FLOAT_API
|
||||
(void)analysis;
|
||||
#else
|
||||
if (analysis->valid)
|
||||
{
|
||||
for (i=start;i<IMIN(LEAK_BANDS, end);i++)
|
||||
follower[i] = follower[i] + QCONST16(1.f/64.f, DB_SHIFT)*analysis->leak_boost[i];
|
||||
}
|
||||
#endif
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
int width;
|
||||
int boost;
|
||||
int boost_bits;
|
||||
|
||||
follower[i] = MIN16(follower[i], QCONST16(4, DB_SHIFT));
|
||||
|
||||
width = C*(eBands[i+1]-eBands[i])<<LM;
|
||||
|
@ -1042,11 +1139,11 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
boost = (int)SHR32(EXTEND32(follower[i])*width/6,DB_SHIFT);
|
||||
boost_bits = boost*6<<BITRES;
|
||||
}
|
||||
/* For CBR and non-transient CVBR frames, limit dynalloc to 1/4 of the bits */
|
||||
/* For CBR and non-transient CVBR frames, limit dynalloc to 2/3 of the bits */
|
||||
if ((!vbr || (constrained_vbr&&!isTransient))
|
||||
&& (tot_boost+boost_bits)>>BITRES>>3 > effectiveBytes/4)
|
||||
&& (tot_boost+boost_bits)>>BITRES>>3 > 2*effectiveBytes/3)
|
||||
{
|
||||
opus_int32 cap = ((effectiveBytes/4)<<BITRES<<3);
|
||||
opus_int32 cap = ((2*effectiveBytes/3)<<BITRES<<3);
|
||||
offsets[i] = cap-tot_boost;
|
||||
tot_boost = cap;
|
||||
break;
|
||||
|
@ -1055,6 +1152,9 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
tot_boost += boost_bits;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i=start;i<end;i++)
|
||||
importance[i] = 13;
|
||||
}
|
||||
*tot_boost_ = tot_boost;
|
||||
RESTORE_STACK;
|
||||
|
@ -1063,7 +1163,7 @@ static opus_val16 dynalloc_analysis(const opus_val16 *bandLogE, const opus_val16
|
|||
|
||||
|
||||
static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem, int CC, int N,
|
||||
int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes)
|
||||
int prefilter_tapset, int *pitch, opus_val16 *gain, int *qgain, int enabled, int nbAvailableBytes, AnalysisInfo *analysis)
|
||||
{
|
||||
int c;
|
||||
VARDECL(celt_sig, _pre);
|
||||
|
@ -1119,7 +1219,12 @@ static int run_prefilter(CELTEncoder *st, celt_sig *in, celt_sig *prefilter_mem,
|
|||
gain1 = 0;
|
||||
pitch_index = COMBFILTER_MINPERIOD;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
if (analysis->valid)
|
||||
gain1 = (opus_val16)(gain1 * analysis->max_pitch_ratio);
|
||||
#else
|
||||
(void)analysis;
|
||||
#endif
|
||||
/* Gain threshold for enabling the prefilter/postfilter */
|
||||
pf_threshold = QCONST16(.2f,15);
|
||||
|
||||
|
@ -1193,7 +1298,7 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32
|
|||
int LM, opus_int32 bitrate, int lastCodedBands, int C, int intensity,
|
||||
int constrained_vbr, opus_val16 stereo_saving, int tot_boost,
|
||||
opus_val16 tf_estimate, int pitch_change, opus_val16 maxDepth,
|
||||
int variable_duration, int lfe, int has_surround_mask, opus_val16 surround_masking,
|
||||
int lfe, int has_surround_mask, opus_val16 surround_masking,
|
||||
opus_val16 temporal_vbr)
|
||||
{
|
||||
/* The target rate in 8th bits per frame */
|
||||
|
@ -1235,10 +1340,9 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32
|
|||
SHR32(MULT16_16(stereo_saving-QCONST16(0.1f,8),(coded_stereo_dof<<BITRES)),8));
|
||||
}
|
||||
/* Boost the rate according to dynalloc (minus the dynalloc average for calibration). */
|
||||
target += tot_boost-(16<<LM);
|
||||
target += tot_boost-(19<<LM);
|
||||
/* Apply transient boost, compensating for average boost. */
|
||||
tf_calibration = variable_duration==OPUS_FRAMESIZE_VARIABLE ?
|
||||
QCONST16(0.02f,14) : QCONST16(0.04f,14);
|
||||
tf_calibration = QCONST16(0.044f,14);
|
||||
target += (opus_int32)SHL32(MULT16_32_Q15(tf_estimate-tf_calibration, target),1);
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
|
@ -1249,7 +1353,7 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32
|
|||
float tonal;
|
||||
|
||||
/* Tonality boost (compensating for the average). */
|
||||
tonal = MAX16(0.f,analysis->tonality-.15f)-0.09f;
|
||||
tonal = MAX16(0.f,analysis->tonality-.15f)-0.12f;
|
||||
tonal_target = target + (opus_int32)((coded_bins<<BITRES)*1.2f*tonal);
|
||||
if (pitch_change)
|
||||
tonal_target += (opus_int32)((coded_bins<<BITRES)*.8f);
|
||||
|
@ -1279,21 +1383,11 @@ static int compute_vbr(const CELTMode *mode, AnalysisInfo *analysis, opus_int32
|
|||
/*printf("%f %d\n", maxDepth, floor_depth);*/
|
||||
}
|
||||
|
||||
if ((!has_surround_mask||lfe) && (constrained_vbr || bitrate<64000))
|
||||
/* Make VBR less aggressive for constrained VBR because we can't keep a higher bitrate
|
||||
for long. Needs tuning. */
|
||||
if ((!has_surround_mask||lfe) && constrained_vbr)
|
||||
{
|
||||
opus_val16 rate_factor = Q15ONE;
|
||||
if (bitrate < 64000)
|
||||
{
|
||||
#ifdef FIXED_POINT
|
||||
rate_factor = MAX16(0,(bitrate-32000));
|
||||
#else
|
||||
rate_factor = MAX16(0,(1.f/32768)*(bitrate-32000));
|
||||
#endif
|
||||
}
|
||||
if (constrained_vbr)
|
||||
rate_factor = MIN16(rate_factor, QCONST16(0.67f, 15));
|
||||
target = base_target + (opus_int32)MULT16_32_Q15(rate_factor, target-base_target);
|
||||
|
||||
target = base_target + (opus_int32)MULT16_32_Q15(QCONST16(0.67f, 15), target-base_target);
|
||||
}
|
||||
|
||||
if (!has_surround_mask && tf_estimate < QCONST16(.2f, 14))
|
||||
|
@ -1327,11 +1421,13 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
VARDECL(int, pulses);
|
||||
VARDECL(int, cap);
|
||||
VARDECL(int, offsets);
|
||||
VARDECL(int, importance);
|
||||
VARDECL(int, spread_weight);
|
||||
VARDECL(int, fine_priority);
|
||||
VARDECL(int, tf_res);
|
||||
VARDECL(unsigned char, collapse_masks);
|
||||
celt_sig *prefilter_mem;
|
||||
opus_val16 *oldBandE, *oldLogE, *oldLogE2;
|
||||
opus_val16 *oldBandE, *oldLogE, *oldLogE2, *energyError;
|
||||
int shortBlocks=0;
|
||||
int isTransient=0;
|
||||
const int CC = st->channels;
|
||||
|
@ -1343,7 +1439,6 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
int end;
|
||||
int effEnd;
|
||||
int codedBands;
|
||||
int tf_sum;
|
||||
int alloc_trim;
|
||||
int pitch_index=COMBFILTER_MINPERIOD;
|
||||
opus_val16 gain1 = 0;
|
||||
|
@ -1355,6 +1450,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
opus_int32 total_boost;
|
||||
opus_int32 balance;
|
||||
opus_int32 tell;
|
||||
opus_int32 tell0_frac;
|
||||
int prefilter_tapset=0;
|
||||
int pf_on;
|
||||
int anti_collapse_rsv;
|
||||
|
@ -1376,7 +1472,10 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
opus_val16 surround_masking=0;
|
||||
opus_val16 temporal_vbr=0;
|
||||
opus_val16 surround_trim = 0;
|
||||
opus_int32 equiv_rate = 510000;
|
||||
opus_int32 equiv_rate;
|
||||
int hybrid;
|
||||
int weak_transient = 0;
|
||||
int enable_tf_analysis;
|
||||
VARDECL(opus_val16, surround_dynalloc);
|
||||
ALLOC_STACK;
|
||||
|
||||
|
@ -1386,6 +1485,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
eBands = mode->eBands;
|
||||
start = st->start;
|
||||
end = st->end;
|
||||
hybrid = start != 0;
|
||||
tf_estimate = 0;
|
||||
if (nbCompressedBytes<2 || pcm==NULL)
|
||||
{
|
||||
|
@ -1409,12 +1509,14 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
oldBandE = (opus_val16*)(st->in_mem+CC*(overlap+COMBFILTER_MAXPERIOD));
|
||||
oldLogE = oldBandE + CC*nbEBands;
|
||||
oldLogE2 = oldLogE + CC*nbEBands;
|
||||
energyError = oldLogE2 + CC*nbEBands;
|
||||
|
||||
if (enc==NULL)
|
||||
{
|
||||
tell=1;
|
||||
tell0_frac=tell=1;
|
||||
nbFilledBytes=0;
|
||||
} else {
|
||||
tell0_frac=ec_tell_frac(enc);
|
||||
tell=ec_tell(enc);
|
||||
nbFilledBytes=(tell+4)>>3;
|
||||
}
|
||||
|
@ -1467,10 +1569,11 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
if (st->bitrate!=OPUS_BITRATE_MAX)
|
||||
nbCompressedBytes = IMAX(2, IMIN(nbCompressedBytes,
|
||||
(tmp+4*mode->Fs)/(8*mode->Fs)-!!st->signalling));
|
||||
effectiveBytes = nbCompressedBytes;
|
||||
effectiveBytes = nbCompressedBytes - nbFilledBytes;
|
||||
}
|
||||
equiv_rate = ((opus_int32)nbCompressedBytes*8*50 >> (3-LM)) - (40*C+20)*((400>>LM) - 50);
|
||||
if (st->bitrate != OPUS_BITRATE_MAX)
|
||||
equiv_rate = st->bitrate - (40*C+20)*((400>>LM) - 50);
|
||||
equiv_rate = IMIN(equiv_rate, st->bitrate - (40*C+20)*((400>>LM) - 50));
|
||||
|
||||
if (enc==NULL)
|
||||
{
|
||||
|
@ -1558,17 +1661,17 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
{
|
||||
int enabled;
|
||||
int qg;
|
||||
enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && start==0 && !silence && !st->disable_pf
|
||||
&& st->complexity >= 5 && !(st->consec_transient && LM!=3 && st->variable_duration==OPUS_FRAMESIZE_VARIABLE);
|
||||
enabled = ((st->lfe&&nbAvailableBytes>3) || nbAvailableBytes>12*C) && !hybrid && !silence && !st->disable_pf
|
||||
&& st->complexity >= 5;
|
||||
|
||||
prefilter_tapset = st->tapset_decision;
|
||||
pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes);
|
||||
pf_on = run_prefilter(st, in, prefilter_mem, CC, N, prefilter_tapset, &pitch_index, &gain1, &qg, enabled, nbAvailableBytes, &st->analysis);
|
||||
if ((gain1 > QCONST16(.4f,15) || st->prefilter_gain > QCONST16(.4f,15)) && (!st->analysis.valid || st->analysis.tonality > .3)
|
||||
&& (pitch_index > 1.26*st->prefilter_period || pitch_index < .79*st->prefilter_period))
|
||||
pitch_change = 1;
|
||||
if (pf_on==0)
|
||||
{
|
||||
if(start==0 && tell+16<=total_bits)
|
||||
if(!hybrid && tell+16<=total_bits)
|
||||
ec_enc_bit_logp(enc, 0, 1);
|
||||
} else {
|
||||
/*This block is not gated by a total bits check only because
|
||||
|
@ -1589,8 +1692,12 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
shortBlocks = 0;
|
||||
if (st->complexity >= 1 && !st->lfe)
|
||||
{
|
||||
/* Reduces the likelihood of energy instability on fricatives at low bitrate
|
||||
in hybrid mode. It seems like we still want to have real transients on vowels
|
||||
though (small SILK quantization offset value). */
|
||||
int allow_weak_transients = hybrid && effectiveBytes<15 && st->silk_info.signalType != 2;
|
||||
isTransient = transient_analysis(in, N+overlap, CC,
|
||||
&tf_estimate, &tf_chan);
|
||||
&tf_estimate, &tf_chan, allow_weak_transients, &weak_transient);
|
||||
}
|
||||
if (LM>0 && ec_tell(enc)+3<=total_bits)
|
||||
{
|
||||
|
@ -1610,16 +1717,19 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
if (secondMdct)
|
||||
{
|
||||
compute_mdcts(mode, 0, in, freq, C, CC, LM, st->upsample, st->arch);
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM);
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch);
|
||||
amp2Log2(mode, effEnd, end, bandE, bandLogE2, C);
|
||||
for (i=0;i<C*nbEBands;i++)
|
||||
bandLogE2[i] += HALF16(SHL16(LM, DB_SHIFT));
|
||||
}
|
||||
|
||||
compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
|
||||
/* This should catch any NaN in the CELT input. Since we're not supposed to see any (they're filtered
|
||||
at the Opus layer), just abort. */
|
||||
celt_assert(!celt_isnan(freq[0]) && (C==1 || !celt_isnan(freq[N])));
|
||||
if (CC==2&&C==1)
|
||||
tf_chan = 0;
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM);
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch);
|
||||
|
||||
if (st->lfe)
|
||||
{
|
||||
|
@ -1634,7 +1744,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
ALLOC(surround_dynalloc, C*nbEBands, opus_val16);
|
||||
OPUS_CLEAR(surround_dynalloc, end);
|
||||
/* This computes how much masking takes place between surround channels */
|
||||
if (start==0&&st->energy_mask&&!st->lfe)
|
||||
if (!hybrid&&st->energy_mask&&!st->lfe)
|
||||
{
|
||||
int mask_end;
|
||||
int midband;
|
||||
|
@ -1736,14 +1846,14 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
|
||||
/* Last chance to catch any transient we might have missed in the
|
||||
time-domain analysis */
|
||||
if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe)
|
||||
if (LM>0 && ec_tell(enc)+3<=total_bits && !isTransient && st->complexity>=5 && !st->lfe && !hybrid)
|
||||
{
|
||||
if (patch_transient_decision(bandLogE, oldBandE, nbEBands, start, end, C))
|
||||
{
|
||||
isTransient = 1;
|
||||
shortBlocks = M;
|
||||
compute_mdcts(mode, shortBlocks, in, freq, C, CC, LM, st->upsample, st->arch);
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM);
|
||||
compute_band_energies(mode, freq, bandE, effEnd, C, LM, st->arch);
|
||||
amp2Log2(mode, effEnd, end, bandE, bandLogE, C);
|
||||
/* Compensate for the scaling of short vs long mdcts */
|
||||
for (i=0;i<C*nbEBands;i++)
|
||||
|
@ -1760,31 +1870,59 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
/* Band normalisation */
|
||||
normalise_bands(mode, freq, X, bandE, effEnd, C, M);
|
||||
|
||||
enable_tf_analysis = effectiveBytes>=15*C && !hybrid && st->complexity>=2 && !st->lfe;
|
||||
|
||||
ALLOC(offsets, nbEBands, int);
|
||||
ALLOC(importance, nbEBands, int);
|
||||
ALLOC(spread_weight, nbEBands, int);
|
||||
|
||||
maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
|
||||
st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
|
||||
eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc, &st->analysis, importance, spread_weight);
|
||||
|
||||
ALLOC(tf_res, nbEBands, int);
|
||||
/* Disable variable tf resolution for hybrid and at very low bitrate */
|
||||
if (effectiveBytes>=15*C && start==0 && st->complexity>=2 && !st->lfe)
|
||||
if (enable_tf_analysis)
|
||||
{
|
||||
int lambda;
|
||||
if (effectiveBytes<40)
|
||||
lambda = 12;
|
||||
else if (effectiveBytes<60)
|
||||
lambda = 6;
|
||||
else if (effectiveBytes<100)
|
||||
lambda = 4;
|
||||
else
|
||||
lambda = 3;
|
||||
lambda*=2;
|
||||
tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, &tf_sum, tf_estimate, tf_chan);
|
||||
lambda = IMAX(80, 20480/effectiveBytes + 2);
|
||||
tf_select = tf_analysis(mode, effEnd, isTransient, tf_res, lambda, X, N, LM, tf_estimate, tf_chan, importance);
|
||||
for (i=effEnd;i<end;i++)
|
||||
tf_res[i] = tf_res[effEnd-1];
|
||||
} else if (hybrid && weak_transient)
|
||||
{
|
||||
/* For weak transients, we rely on the fact that improving time resolution using
|
||||
TF on a long window is imperfect and will not result in an energy collapse at
|
||||
low bitrate. */
|
||||
for (i=0;i<end;i++)
|
||||
tf_res[i] = 1;
|
||||
tf_select=0;
|
||||
} else if (hybrid && effectiveBytes<15 && st->silk_info.signalType != 2)
|
||||
{
|
||||
/* For low bitrate hybrid, we force temporal resolution to 5 ms rather than 2.5 ms. */
|
||||
for (i=0;i<end;i++)
|
||||
tf_res[i] = 0;
|
||||
tf_select=isTransient;
|
||||
} else {
|
||||
tf_sum = 0;
|
||||
for (i=0;i<end;i++)
|
||||
tf_res[i] = isTransient;
|
||||
tf_select=0;
|
||||
}
|
||||
|
||||
ALLOC(error, C*nbEBands, opus_val16);
|
||||
c=0;
|
||||
do {
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
/* When the energy is stable, slightly bias energy quantization towards
|
||||
the previous error to make the gain more stable (a constant offset is
|
||||
better than fluctuations). */
|
||||
if (ABS32(SUB32(bandLogE[i+c*nbEBands], oldBandE[i+c*nbEBands])) < QCONST16(2.f, DB_SHIFT))
|
||||
{
|
||||
bandLogE[i+c*nbEBands] -= MULT16_16_Q15(energyError[i+c*nbEBands], QCONST16(0.25f, 15));
|
||||
}
|
||||
}
|
||||
} while (++c < C);
|
||||
quant_coarse_energy(mode, start, end, effEnd, bandLogE,
|
||||
oldBandE, total_bits, error, enc,
|
||||
C, LM, nbAvailableBytes, st->force_intra,
|
||||
|
@ -1798,7 +1936,15 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
{
|
||||
st->tapset_decision = 0;
|
||||
st->spread_decision = SPREAD_NORMAL;
|
||||
} else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C || start != 0)
|
||||
} else if (hybrid)
|
||||
{
|
||||
if (st->complexity == 0)
|
||||
st->spread_decision = SPREAD_NONE;
|
||||
else if (isTransient)
|
||||
st->spread_decision = SPREAD_NORMAL;
|
||||
else
|
||||
st->spread_decision = SPREAD_AGGRESSIVE;
|
||||
} else if (shortBlocks || st->complexity < 3 || nbAvailableBytes < 10*C)
|
||||
{
|
||||
if (st->complexity == 0)
|
||||
st->spread_decision = SPREAD_NONE;
|
||||
|
@ -1822,7 +1968,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
{
|
||||
st->spread_decision = spreading_decision(mode, X,
|
||||
&st->tonal_average, st->spread_decision, &st->hf_average,
|
||||
&st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M);
|
||||
&st->tapset_decision, pf_on&&!shortBlocks, effEnd, C, M, spread_weight);
|
||||
}
|
||||
/*printf("%d %d\n", st->tapset_decision, st->spread_decision);*/
|
||||
/*printf("%f %d %f %d\n\n", st->analysis.tonality, st->spread_decision, st->analysis.tonality_slope, st->tapset_decision);*/
|
||||
|
@ -1830,11 +1976,6 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
ec_enc_icdf(enc, st->spread_decision, spread_icdf, 5);
|
||||
}
|
||||
|
||||
ALLOC(offsets, nbEBands, int);
|
||||
|
||||
maxDepth = dynalloc_analysis(bandLogE, bandLogE2, nbEBands, start, end, C, offsets,
|
||||
st->lsb_depth, mode->logN, isTransient, st->vbr, st->constrained_vbr,
|
||||
eBands, LM, effectiveBytes, &tot_boost, st->lfe, surround_dynalloc);
|
||||
/* For LFE, everything interesting is in the first band */
|
||||
if (st->lfe)
|
||||
offsets[0] = IMIN(8, effectiveBytes/3);
|
||||
|
@ -1896,12 +2037,15 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
alloc_trim = 5;
|
||||
if (tell+(6<<BITRES) <= total_bits - total_boost)
|
||||
{
|
||||
if (st->lfe)
|
||||
if (start > 0 || st->lfe)
|
||||
{
|
||||
st->stereo_saving = 0;
|
||||
alloc_trim = 5;
|
||||
else
|
||||
} else {
|
||||
alloc_trim = alloc_trim_analysis(mode, X, bandLogE,
|
||||
end, LM, C, N, &st->analysis, &st->stereo_saving, tf_estimate,
|
||||
st->intensity, surround_trim, st->arch);
|
||||
st->intensity, surround_trim, equiv_rate, st->arch);
|
||||
}
|
||||
ec_enc_icdf(enc, alloc_trim, trim_icdf, 7);
|
||||
tell = ec_tell_frac(enc);
|
||||
}
|
||||
|
@ -1919,17 +2063,36 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
/* Don't attempt to use more than 510 kb/s, even for frames smaller than 20 ms.
|
||||
The CELT allocator will just not be able to use more than that anyway. */
|
||||
nbCompressedBytes = IMIN(nbCompressedBytes,1275>>(3-LM));
|
||||
base_target = vbr_rate - ((40*C+20)<<BITRES);
|
||||
if (!hybrid)
|
||||
{
|
||||
base_target = vbr_rate - ((40*C+20)<<BITRES);
|
||||
} else {
|
||||
base_target = IMAX(0, vbr_rate - ((9*C+4)<<BITRES));
|
||||
}
|
||||
|
||||
if (st->constrained_vbr)
|
||||
base_target += (st->vbr_offset>>lm_diff);
|
||||
|
||||
target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
|
||||
if (!hybrid)
|
||||
{
|
||||
target = compute_vbr(mode, &st->analysis, base_target, LM, equiv_rate,
|
||||
st->lastCodedBands, C, st->intensity, st->constrained_vbr,
|
||||
st->stereo_saving, tot_boost, tf_estimate, pitch_change, maxDepth,
|
||||
st->variable_duration, st->lfe, st->energy_mask!=NULL, surround_masking,
|
||||
st->lfe, st->energy_mask!=NULL, surround_masking,
|
||||
temporal_vbr);
|
||||
|
||||
} else {
|
||||
target = base_target;
|
||||
/* Tonal frames (offset<100) need more bits than noisy (offset>100) ones. */
|
||||
if (st->silk_info.offset < 100) target += 12 << BITRES >> (3-LM);
|
||||
if (st->silk_info.offset > 100) target -= 18 << BITRES >> (3-LM);
|
||||
/* Boosting bitrate on transients and vowels with significant temporal
|
||||
spikes. */
|
||||
target += (opus_int32)MULT16_16_Q14(tf_estimate-QCONST16(.25f,14), (50<<BITRES));
|
||||
/* If we have a strong transient, let's make sure it has enough bits to code
|
||||
the first two bands, so that it can use folding rather than noise. */
|
||||
if (tf_estimate > QCONST16(.7f,14))
|
||||
target = IMAX(target, 50<<BITRES);
|
||||
}
|
||||
/* The current offset is removed from the target and the space used
|
||||
so far is added*/
|
||||
target=target+tell;
|
||||
|
@ -1937,11 +2100,16 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
result in the encoder running out of bits.
|
||||
The margin of 2 bytes ensures that none of the bust-prevention logic
|
||||
in the decoder will have triggered so far. */
|
||||
min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2 - nbFilledBytes;
|
||||
min_allowed = ((tell+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3)) + 2;
|
||||
/* Take into account the 37 bits we need to have left in the packet to
|
||||
signal a redundant frame in hybrid mode. Creating a shorter packet would
|
||||
create an entropy coder desync. */
|
||||
if (hybrid)
|
||||
min_allowed = IMAX(min_allowed, (tell0_frac+(37<<BITRES)+total_boost+(1<<(BITRES+3))-1)>>(BITRES+3));
|
||||
|
||||
nbAvailableBytes = (target+(1<<(BITRES+2)))>>(BITRES+3);
|
||||
nbAvailableBytes = IMAX(min_allowed,nbAvailableBytes);
|
||||
nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes) - nbFilledBytes;
|
||||
nbAvailableBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
|
||||
|
||||
/* By how much did we "miss" the target on that frame */
|
||||
delta = target - vbr_rate;
|
||||
|
@ -1988,7 +2156,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
st->vbr_reservoir = 0;
|
||||
/*printf ("+%d\n", adjust);*/
|
||||
}
|
||||
nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes+nbFilledBytes);
|
||||
nbCompressedBytes = IMIN(nbCompressedBytes,nbAvailableBytes);
|
||||
/*printf("%d\n", nbCompressedBytes*50*8);*/
|
||||
/* This moves the raw bits to take into account the new compressed size */
|
||||
ec_enc_shrink(enc, nbCompressedBytes);
|
||||
|
@ -2023,7 +2191,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
#endif
|
||||
if (st->lfe)
|
||||
signalBandwidth = 1;
|
||||
codedBands = compute_allocation(mode, start, end, offsets, cap,
|
||||
codedBands = clt_compute_allocation(mode, start, end, offsets, cap,
|
||||
alloc_trim, &st->intensity, &dual_stereo, bits, &balance, pulses,
|
||||
fine_quant, fine_priority, C, LM, enc, 1, st->lastCodedBands, signalBandwidth);
|
||||
if (st->lastCodedBands)
|
||||
|
@ -2038,7 +2206,7 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
quant_all_bands(1, mode, start, end, X, C==2 ? X+N : NULL, collapse_masks,
|
||||
bandE, pulses, shortBlocks, st->spread_decision,
|
||||
dual_stereo, st->intensity, tf_res, nbCompressedBytes*(8<<BITRES)-anti_collapse_rsv,
|
||||
balance, enc, LM, codedBands, &st->rng, st->arch);
|
||||
balance, enc, LM, codedBands, &st->rng, st->complexity, st->arch, st->disable_inv);
|
||||
|
||||
if (anti_collapse_rsv > 0)
|
||||
{
|
||||
|
@ -2049,6 +2217,14 @@ int celt_encode_with_ec(CELTEncoder * OPUS_RESTRICT st, const opus_val16 * pcm,
|
|||
ec_enc_bits(enc, anti_collapse_on, 1);
|
||||
}
|
||||
quant_energy_finalise(mode, start, end, oldBandE, error, fine_quant, fine_priority, nbCompressedBytes*8-ec_tell(enc), enc, C);
|
||||
OPUS_CLEAR(energyError, nbEBands*CC);
|
||||
c=0;
|
||||
do {
|
||||
for (i=start;i<end;i++)
|
||||
{
|
||||
energyError[i+c*nbEBands] = MAX16(-QCONST16(0.5f, 15), MIN16(QCONST16(0.5f, 15), error[i+c*nbEBands]));
|
||||
}
|
||||
} while (++c < C);
|
||||
|
||||
if (silence)
|
||||
{
|
||||
|
@ -2321,10 +2497,24 @@ int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
|
|||
*value=st->lsb_depth;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_EXPERT_FRAME_DURATION_REQUEST:
|
||||
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 value = va_arg(ap, opus_int32);
|
||||
st->variable_duration = value;
|
||||
if(value<0 || value>1)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
st->disable_inv = value;
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = st->disable_inv;
|
||||
}
|
||||
break;
|
||||
case OPUS_RESET_STATE:
|
||||
|
@ -2368,6 +2558,13 @@ int opus_custom_encoder_ctl(CELTEncoder * OPUS_RESTRICT st, int request, ...)
|
|||
OPUS_COPY(&st->analysis, info, 1);
|
||||
}
|
||||
break;
|
||||
case CELT_SET_SILK_INFO_REQUEST:
|
||||
{
|
||||
SILKInfo *info = va_arg(ap, SILKInfo *);
|
||||
if (info)
|
||||
OPUS_COPY(&st->silk_info, info, 1);
|
||||
}
|
||||
break;
|
||||
case CELT_GET_MODE_REQUEST:
|
||||
{
|
||||
const CELTMode ** value = va_arg(ap, const CELTMode**);
|
||||
|
|
|
@ -89,58 +89,40 @@ int p
|
|||
|
||||
|
||||
void celt_fir_c(
|
||||
const opus_val16 *_x,
|
||||
const opus_val16 *x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *_y,
|
||||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch)
|
||||
{
|
||||
int i,j;
|
||||
VARDECL(opus_val16, rnum);
|
||||
VARDECL(opus_val16, x);
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert(x != y);
|
||||
ALLOC(rnum, ord, opus_val16);
|
||||
ALLOC(x, N+ord, opus_val16);
|
||||
for(i=0;i<ord;i++)
|
||||
rnum[i] = num[ord-i-1];
|
||||
for(i=0;i<ord;i++)
|
||||
x[i] = mem[ord-i-1];
|
||||
for (i=0;i<N;i++)
|
||||
x[i+ord]=_x[i];
|
||||
for(i=0;i<ord;i++)
|
||||
mem[i] = _x[N-i-1];
|
||||
#ifdef SMALL_FOOTPRINT
|
||||
(void)arch;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
|
||||
for (j=0;j<ord;j++)
|
||||
{
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j]);
|
||||
}
|
||||
_y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
|
||||
}
|
||||
#else
|
||||
for (i=0;i<N-3;i+=4)
|
||||
{
|
||||
opus_val32 sum[4]={0,0,0,0};
|
||||
xcorr_kernel(rnum, x+i, sum, ord, arch);
|
||||
_y[i ] = SATURATE16(ADD32(EXTEND32(_x[i ]), PSHR32(sum[0], SIG_SHIFT)));
|
||||
_y[i+1] = SATURATE16(ADD32(EXTEND32(_x[i+1]), PSHR32(sum[1], SIG_SHIFT)));
|
||||
_y[i+2] = SATURATE16(ADD32(EXTEND32(_x[i+2]), PSHR32(sum[2], SIG_SHIFT)));
|
||||
_y[i+3] = SATURATE16(ADD32(EXTEND32(_x[i+3]), PSHR32(sum[3], SIG_SHIFT)));
|
||||
opus_val32 sum[4];
|
||||
sum[0] = SHL32(EXTEND32(x[i ]), SIG_SHIFT);
|
||||
sum[1] = SHL32(EXTEND32(x[i+1]), SIG_SHIFT);
|
||||
sum[2] = SHL32(EXTEND32(x[i+2]), SIG_SHIFT);
|
||||
sum[3] = SHL32(EXTEND32(x[i+3]), SIG_SHIFT);
|
||||
xcorr_kernel(rnum, x+i-ord, sum, ord, arch);
|
||||
y[i ] = ROUND16(sum[0], SIG_SHIFT);
|
||||
y[i+1] = ROUND16(sum[1], SIG_SHIFT);
|
||||
y[i+2] = ROUND16(sum[2], SIG_SHIFT);
|
||||
y[i+3] = ROUND16(sum[3], SIG_SHIFT);
|
||||
}
|
||||
for (;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = 0;
|
||||
opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
|
||||
for (j=0;j<ord;j++)
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j]);
|
||||
_y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j-ord]);
|
||||
y[i] = ROUND16(sum, SIG_SHIFT);
|
||||
}
|
||||
#endif
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
||||
|
@ -166,7 +148,7 @@ void celt_iir(const opus_val32 *_x,
|
|||
{
|
||||
mem[j]=mem[j-1];
|
||||
}
|
||||
mem[0] = ROUND16(sum,SIG_SHIFT);
|
||||
mem[0] = SROUND16(sum, SIG_SHIFT);
|
||||
_y[i] = sum;
|
||||
}
|
||||
#else
|
||||
|
@ -195,20 +177,20 @@ void celt_iir(const opus_val32 *_x,
|
|||
xcorr_kernel(rden, y+i, sum, ord, arch);
|
||||
|
||||
/* Patch up the result to compensate for the fact that this is an IIR */
|
||||
y[i+ord ] = -ROUND16(sum[0],SIG_SHIFT);
|
||||
y[i+ord ] = -SROUND16(sum[0],SIG_SHIFT);
|
||||
_y[i ] = sum[0];
|
||||
sum[1] = MAC16_16(sum[1], y[i+ord ], den[0]);
|
||||
y[i+ord+1] = -ROUND16(sum[1],SIG_SHIFT);
|
||||
y[i+ord+1] = -SROUND16(sum[1],SIG_SHIFT);
|
||||
_y[i+1] = sum[1];
|
||||
sum[2] = MAC16_16(sum[2], y[i+ord+1], den[0]);
|
||||
sum[2] = MAC16_16(sum[2], y[i+ord ], den[1]);
|
||||
y[i+ord+2] = -ROUND16(sum[2],SIG_SHIFT);
|
||||
y[i+ord+2] = -SROUND16(sum[2],SIG_SHIFT);
|
||||
_y[i+2] = sum[2];
|
||||
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord+2], den[0]);
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord+1], den[1]);
|
||||
sum[3] = MAC16_16(sum[3], y[i+ord ], den[2]);
|
||||
y[i+ord+3] = -ROUND16(sum[3],SIG_SHIFT);
|
||||
y[i+ord+3] = -SROUND16(sum[3],SIG_SHIFT);
|
||||
_y[i+3] = sum[3];
|
||||
}
|
||||
for (;i<N;i++)
|
||||
|
@ -216,7 +198,7 @@ void celt_iir(const opus_val32 *_x,
|
|||
opus_val32 sum = _x[i];
|
||||
for (j=0;j<ord;j++)
|
||||
sum -= MULT16_16(rden[j],y[i+j]);
|
||||
y[i+ord] = ROUND16(sum,SIG_SHIFT);
|
||||
y[i+ord] = SROUND16(sum,SIG_SHIFT);
|
||||
_y[i] = sum;
|
||||
}
|
||||
for(i=0;i<ord;i++)
|
||||
|
|
|
@ -45,12 +45,11 @@ void celt_fir_c(
|
|||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch);
|
||||
|
||||
#if !defined(OVERRIDE_CELT_FIR)
|
||||
#define celt_fir(x, num, y, N, ord, mem, arch) \
|
||||
(celt_fir_c(x, num, y, N, ord, mem, arch))
|
||||
#define celt_fir(x, num, y, N, ord, arch) \
|
||||
(celt_fir_c(x, num, y, N, ord, arch))
|
||||
#endif
|
||||
|
||||
void celt_iir(const opus_val32 *x,
|
||||
|
|
|
@ -482,7 +482,7 @@ static opus_val32 cwrsi(int _n,int _k,opus_uint32 _i,int *_y){
|
|||
k0=_k;
|
||||
q=row[_n];
|
||||
if(q>_i){
|
||||
celt_assert(p>q);
|
||||
celt_sig_assert(p>q);
|
||||
_k=_n;
|
||||
do p=CELT_PVQ_U_ROW[--_k][_n];
|
||||
while(p>_i);
|
||||
|
|
|
@ -122,7 +122,7 @@ opus_uint32 ec_tell_frac(ec_ctx *_this);
|
|||
|
||||
/* Tested exhaustively for all n and for 1<=d<=256 */
|
||||
static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) {
|
||||
celt_assert(d>0);
|
||||
celt_sig_assert(d>0);
|
||||
#ifdef USE_SMALL_DIV_TABLE
|
||||
if (d>256)
|
||||
return n/d;
|
||||
|
@ -138,7 +138,7 @@ static OPUS_INLINE opus_uint32 celt_udiv(opus_uint32 n, opus_uint32 d) {
|
|||
}
|
||||
|
||||
static OPUS_INLINE opus_int32 celt_sudiv(opus_int32 n, opus_int32 d) {
|
||||
celt_assert(d>0);
|
||||
celt_sig_assert(d>0);
|
||||
#ifdef USE_SMALL_DIV_TABLE
|
||||
if (n<0)
|
||||
return -(opus_int32)celt_udiv(-n, d);
|
||||
|
|
|
@ -85,7 +85,7 @@ int ec_dec_icdf(ec_dec *_this,const unsigned char *_icdf,unsigned _ftb);
|
|||
The bits must have been encoded with ec_enc_uint().
|
||||
No call to ec_dec_update() is necessary after this call.
|
||||
_ft: The number of integers that can be decoded (one more than the max).
|
||||
This must be at least one, and no more than 2**32-1.
|
||||
This must be at least 2, and no more than 2**32-1.
|
||||
Return: The decoded bits.*/
|
||||
opus_uint32 ec_dec_uint(ec_dec *_this,opus_uint32 _ft);
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@ void ec_enc_icdf(ec_enc *_this,int _s,const unsigned char *_icdf,unsigned _ftb);
|
|||
/*Encodes a raw unsigned integer in the stream.
|
||||
_fl: The integer to encode.
|
||||
_ft: The number of integers that can be encoded (one more than the max).
|
||||
This must be at least one, and no more than 2**32-1.*/
|
||||
This must be at least 2, and no more than 2**32-1.*/
|
||||
void ec_enc_uint(ec_enc *_this,opus_uint32 _fl,opus_uint32 _ft);
|
||||
|
||||
/*Encodes a sequence of raw bits in the stream.
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* Copyright (C) 2003 Jean-Marc Valin */
|
||||
/**
|
||||
@file fixed_c5x.h
|
||||
@brief Fixed-point operations for the TI C5x DSP family
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_C5X_H
|
||||
#define FIXED_C5X_H
|
||||
|
||||
#include "dsplib.h"
|
||||
|
||||
#undef IMUL32
|
||||
static OPUS_INLINE long IMUL32(long i, long j)
|
||||
{
|
||||
long ac0, ac1;
|
||||
ac0 = _lmpy(i>>16,j);
|
||||
ac1 = ac0 + _lmpy(i,j>>16);
|
||||
return _lmpyu(i,j) + (ac1<<16);
|
||||
}
|
||||
|
||||
#undef MAX16
|
||||
#define MAX16(a,b) _max(a,b)
|
||||
|
||||
#undef MIN16
|
||||
#define MIN16(a,b) _min(a,b)
|
||||
|
||||
#undef MAX32
|
||||
#define MAX32(a,b) _lmax(a,b)
|
||||
|
||||
#undef MIN32
|
||||
#define MIN32(a,b) _lmin(a,b)
|
||||
|
||||
#undef VSHR32
|
||||
#define VSHR32(a, shift) _lshl(a,-(shift))
|
||||
|
||||
#undef MULT16_16_Q15
|
||||
#define MULT16_16_Q15(a,b) (_smpy(a,b))
|
||||
|
||||
#undef MULT16_16SU
|
||||
#define MULT16_16SU(a,b) _lmpysu(a,b)
|
||||
|
||||
#undef MULT_16_16
|
||||
#define MULT_16_16(a,b) _lmpy(a,b)
|
||||
|
||||
/* FIXME: This is technically incorrect and is bound to cause problems. Is there any cleaner solution? */
|
||||
#undef MULT16_32_Q15
|
||||
#define MULT16_32_Q15(a,b) ADD32(SHL(MULT16_16((a),SHR((b),16)),1), SHR(MULT16_16SU((a),(b)),15))
|
||||
|
||||
#define celt_ilog2(x) (30 - _lnorm(x))
|
||||
#define OVERRIDE_CELT_ILOG2
|
||||
|
||||
#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len)))
|
||||
#define OVERRIDE_CELT_MAXABS16
|
||||
|
||||
#endif /* FIXED_C5X_H */
|
|
@ -0,0 +1,70 @@
|
|||
/* Copyright (C) 2008 CSIRO */
|
||||
/**
|
||||
@file fixed_c6x.h
|
||||
@brief Fixed-point operations for the TI C6x DSP family
|
||||
*/
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef FIXED_C6X_H
|
||||
#define FIXED_C6X_H
|
||||
|
||||
#undef MULT16_16SU
|
||||
#define MULT16_16SU(a,b) _mpysu(a,b)
|
||||
|
||||
#undef MULT_16_16
|
||||
#define MULT_16_16(a,b) _mpy(a,b)
|
||||
|
||||
#define celt_ilog2(x) (30 - _norm(x))
|
||||
#define OVERRIDE_CELT_ILOG2
|
||||
|
||||
#undef MULT16_32_Q15
|
||||
#define MULT16_32_Q15(a,b) (_mpylill(a, b) >> 15)
|
||||
|
||||
#if 0
|
||||
#include "dsplib.h"
|
||||
|
||||
#undef MAX16
|
||||
#define MAX16(a,b) _max(a,b)
|
||||
|
||||
#undef MIN16
|
||||
#define MIN16(a,b) _min(a,b)
|
||||
|
||||
#undef MAX32
|
||||
#define MAX32(a,b) _lmax(a,b)
|
||||
|
||||
#undef MIN32
|
||||
#define MIN32(a,b) _lmin(a,b)
|
||||
|
||||
#undef VSHR32
|
||||
#define VSHR32(a, shift) _lshl(a,-(shift))
|
||||
|
||||
#undef MULT16_16_Q15
|
||||
#define MULT16_16_Q15(a,b) (_smpy(a,b))
|
||||
|
||||
#define celt_maxabs16(x, len) MAX32(EXTEND32(maxval((DATA *)x, len)),-EXTEND32(minval((DATA *)x, len)))
|
||||
#define OVERRIDE_CELT_MAXABS16
|
||||
|
||||
#endif /* FIXED_C6X_H */
|
|
@ -59,6 +59,14 @@ extern opus_int64 celt_mips;
|
|||
#define SHR(a,b) SHR32(a,b)
|
||||
#define PSHR(a,b) PSHR32(a,b)
|
||||
|
||||
/** Add two 32-bit values, ignore any overflows */
|
||||
#define ADD32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)+(opus_uint32)(b)))
|
||||
/** Subtract two 32-bit values, ignore any overflows */
|
||||
#define SUB32_ovflw(a,b) (celt_mips+=2,(opus_val32)((opus_uint32)(a)-(opus_uint32)(b)))
|
||||
/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */
|
||||
/** Negate 32-bit value, ignore any overflows */
|
||||
#define NEG32_ovflw(a) (celt_mips+=2,(opus_val32)(0-(opus_uint32)(a)))
|
||||
|
||||
static OPUS_INLINE short NEG16(int x)
|
||||
{
|
||||
int res;
|
||||
|
@ -227,12 +235,11 @@ static OPUS_INLINE int SHL32_(opus_int64 a, int shift, char *file, int line)
|
|||
#define VSHR32(a, shift) (((shift)>0) ? SHR32(a, shift) : SHL32(a, -(shift)))
|
||||
|
||||
#define ROUND16(x,a) (celt_mips--,EXTRACT16(PSHR32((x),(a))))
|
||||
#define SROUND16(x,a) (celt_mips--,EXTRACT16(SATURATE(PSHR32(x,a), 32767)));
|
||||
|
||||
#define HALF16(x) (SHR16(x,1))
|
||||
#define HALF32(x) (SHR32(x,1))
|
||||
|
||||
//#define SHR(a,shift) ((a) >> (shift))
|
||||
//#define SHL(a,shift) ((a) << (shift))
|
||||
|
||||
#define ADD16(a, b) ADD16_(a, b, __FILE__, __LINE__)
|
||||
static OPUS_INLINE short ADD16_(int a, int b, char *file, int line)
|
||||
{
|
||||
|
|
|
@ -104,6 +104,9 @@
|
|||
|
||||
/** Shift by a and round-to-neareast 32-bit value. Result is a 16-bit value */
|
||||
#define ROUND16(x,a) (EXTRACT16(PSHR32((x),(a))))
|
||||
/** Shift by a and round-to-neareast 32-bit value. Result is a saturated 16-bit value */
|
||||
#define SROUND16(x,a) EXTRACT16(SATURATE(PSHR32(x,a), 32767));
|
||||
|
||||
/** Divide by two */
|
||||
#define HALF16(x) (SHR16(x,1))
|
||||
#define HALF32(x) (SHR32(x,1))
|
||||
|
@ -117,6 +120,14 @@
|
|||
/** Subtract two 32-bit values */
|
||||
#define SUB32(a,b) ((opus_val32)(a)-(opus_val32)(b))
|
||||
|
||||
/** Add two 32-bit values, ignore any overflows */
|
||||
#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b)))
|
||||
/** Subtract two 32-bit values, ignore any overflows */
|
||||
#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b)))
|
||||
/* Avoid MSVC warning C4146: unary minus operator applied to unsigned type */
|
||||
/** Negate 32-bit value, ignore any overflows */
|
||||
#define NEG32_ovflw(a) ((opus_val32)(0-(opus_uint32)(a)))
|
||||
|
||||
/** 16x16 multiplication where the result fits in 16 bits */
|
||||
#define MULT16_16_16(a,b) ((((opus_val16)(a))*((opus_val16)(b))))
|
||||
|
||||
|
|
|
@ -61,7 +61,13 @@
|
|||
** the config.h file.
|
||||
*/
|
||||
|
||||
#if (HAVE_LRINTF)
|
||||
/* With GCC, when SSE is available, the fastest conversion is cvtss2si. */
|
||||
#if defined(__GNUC__) && defined(__SSE__)
|
||||
|
||||
#include <xmmintrin.h>
|
||||
static OPUS_INLINE opus_int32 float2int(float x) {return _mm_cvt_ss2si(_mm_set_ss(x));}
|
||||
|
||||
#elif defined(HAVE_LRINTF)
|
||||
|
||||
/* These defines enable functionality introduced with the 1999 ISO C
|
||||
** standard. They must be defined before the inclusion of math.h to
|
||||
|
@ -90,10 +96,10 @@
|
|||
#include <math.h>
|
||||
#define float2int(x) lrint(x)
|
||||
|
||||
#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && defined (_M_X64)
|
||||
#elif (defined(_MSC_VER) && _MSC_VER >= 1400) && (defined(_M_X64) || (defined(_M_IX86_FP) && _M_IX86_FP >= 1))
|
||||
#include <xmmintrin.h>
|
||||
|
||||
__inline long int float2int(float value)
|
||||
static __inline long int float2int(float value)
|
||||
{
|
||||
return _mm_cvtss_si32(_mm_load_ss(&value));
|
||||
}
|
||||
|
@ -104,7 +110,7 @@
|
|||
** Therefore implement OPUS_INLINE versions of these functions here.
|
||||
*/
|
||||
|
||||
__inline long int
|
||||
static __inline long int
|
||||
float2int (float flt)
|
||||
{ int intgr;
|
||||
|
||||
|
|
|
@ -82,8 +82,8 @@ static void kf_bfly2(
|
|||
C_SUB( Fout2[0] , Fout[0] , t );
|
||||
C_ADDTO( Fout[0] , t );
|
||||
|
||||
t.r = S_MUL(Fout2[1].r+Fout2[1].i, tw);
|
||||
t.i = S_MUL(Fout2[1].i-Fout2[1].r, tw);
|
||||
t.r = S_MUL(ADD32_ovflw(Fout2[1].r, Fout2[1].i), tw);
|
||||
t.i = S_MUL(SUB32_ovflw(Fout2[1].i, Fout2[1].r), tw);
|
||||
C_SUB( Fout2[1] , Fout[1] , t );
|
||||
C_ADDTO( Fout[1] , t );
|
||||
|
||||
|
@ -92,8 +92,8 @@ static void kf_bfly2(
|
|||
C_SUB( Fout2[2] , Fout[2] , t );
|
||||
C_ADDTO( Fout[2] , t );
|
||||
|
||||
t.r = S_MUL(Fout2[3].i-Fout2[3].r, tw);
|
||||
t.i = S_MUL(-Fout2[3].i-Fout2[3].r, tw);
|
||||
t.r = S_MUL(SUB32_ovflw(Fout2[3].i, Fout2[3].r), tw);
|
||||
t.i = S_MUL(NEG32_ovflw(ADD32_ovflw(Fout2[3].i, Fout2[3].r)), tw);
|
||||
C_SUB( Fout2[3] , Fout[3] , t );
|
||||
C_ADDTO( Fout[3] , t );
|
||||
Fout += 8;
|
||||
|
@ -126,10 +126,10 @@ static void kf_bfly4(
|
|||
C_ADDTO( *Fout , scratch1 );
|
||||
C_SUB( scratch1 , Fout[1] , Fout[3] );
|
||||
|
||||
Fout[1].r = scratch0.r + scratch1.i;
|
||||
Fout[1].i = scratch0.i - scratch1.r;
|
||||
Fout[3].r = scratch0.r - scratch1.i;
|
||||
Fout[3].i = scratch0.i + scratch1.r;
|
||||
Fout[1].r = ADD32_ovflw(scratch0.r, scratch1.i);
|
||||
Fout[1].i = SUB32_ovflw(scratch0.i, scratch1.r);
|
||||
Fout[3].r = SUB32_ovflw(scratch0.r, scratch1.i);
|
||||
Fout[3].i = ADD32_ovflw(scratch0.i, scratch1.r);
|
||||
Fout+=4;
|
||||
}
|
||||
} else {
|
||||
|
@ -160,10 +160,10 @@ static void kf_bfly4(
|
|||
tw3 += fstride*3;
|
||||
C_ADDTO( *Fout , scratch[3] );
|
||||
|
||||
Fout[m].r = scratch[5].r + scratch[4].i;
|
||||
Fout[m].i = scratch[5].i - scratch[4].r;
|
||||
Fout[m3].r = scratch[5].r - scratch[4].i;
|
||||
Fout[m3].i = scratch[5].i + scratch[4].r;
|
||||
Fout[m].r = ADD32_ovflw(scratch[5].r, scratch[4].i);
|
||||
Fout[m].i = SUB32_ovflw(scratch[5].i, scratch[4].r);
|
||||
Fout[m3].r = SUB32_ovflw(scratch[5].r, scratch[4].i);
|
||||
Fout[m3].i = ADD32_ovflw(scratch[5].i, scratch[4].r);
|
||||
++Fout;
|
||||
}
|
||||
}
|
||||
|
@ -212,18 +212,18 @@ static void kf_bfly3(
|
|||
tw1 += fstride;
|
||||
tw2 += fstride*2;
|
||||
|
||||
Fout[m].r = Fout->r - HALF_OF(scratch[3].r);
|
||||
Fout[m].i = Fout->i - HALF_OF(scratch[3].i);
|
||||
Fout[m].r = SUB32_ovflw(Fout->r, HALF_OF(scratch[3].r));
|
||||
Fout[m].i = SUB32_ovflw(Fout->i, HALF_OF(scratch[3].i));
|
||||
|
||||
C_MULBYSCALAR( scratch[0] , epi3.i );
|
||||
|
||||
C_ADDTO(*Fout,scratch[3]);
|
||||
|
||||
Fout[m2].r = Fout[m].r + scratch[0].i;
|
||||
Fout[m2].i = Fout[m].i - scratch[0].r;
|
||||
Fout[m2].r = ADD32_ovflw(Fout[m].r, scratch[0].i);
|
||||
Fout[m2].i = SUB32_ovflw(Fout[m].i, scratch[0].r);
|
||||
|
||||
Fout[m].r -= scratch[0].i;
|
||||
Fout[m].i += scratch[0].r;
|
||||
Fout[m].r = SUB32_ovflw(Fout[m].r, scratch[0].i);
|
||||
Fout[m].i = ADD32_ovflw(Fout[m].i, scratch[0].r);
|
||||
|
||||
++Fout;
|
||||
} while(--k);
|
||||
|
@ -282,22 +282,22 @@ static void kf_bfly5(
|
|||
C_ADD( scratch[8],scratch[2],scratch[3]);
|
||||
C_SUB( scratch[9],scratch[2],scratch[3]);
|
||||
|
||||
Fout0->r += scratch[7].r + scratch[8].r;
|
||||
Fout0->i += scratch[7].i + scratch[8].i;
|
||||
Fout0->r = ADD32_ovflw(Fout0->r, ADD32_ovflw(scratch[7].r, scratch[8].r));
|
||||
Fout0->i = ADD32_ovflw(Fout0->i, ADD32_ovflw(scratch[7].i, scratch[8].i));
|
||||
|
||||
scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r);
|
||||
scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r);
|
||||
scratch[5].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,ya.r), S_MUL(scratch[8].r,yb.r)));
|
||||
scratch[5].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,ya.r), S_MUL(scratch[8].i,yb.r)));
|
||||
|
||||
scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i);
|
||||
scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i);
|
||||
scratch[6].r = ADD32_ovflw(S_MUL(scratch[10].i,ya.i), S_MUL(scratch[9].i,yb.i));
|
||||
scratch[6].i = NEG32_ovflw(ADD32_ovflw(S_MUL(scratch[10].r,ya.i), S_MUL(scratch[9].r,yb.i)));
|
||||
|
||||
C_SUB(*Fout1,scratch[5],scratch[6]);
|
||||
C_ADD(*Fout4,scratch[5],scratch[6]);
|
||||
|
||||
scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r);
|
||||
scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r);
|
||||
scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i);
|
||||
scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i);
|
||||
scratch[11].r = ADD32_ovflw(scratch[0].r, ADD32_ovflw(S_MUL(scratch[7].r,yb.r), S_MUL(scratch[8].r,ya.r)));
|
||||
scratch[11].i = ADD32_ovflw(scratch[0].i, ADD32_ovflw(S_MUL(scratch[7].i,yb.r), S_MUL(scratch[8].i,ya.r)));
|
||||
scratch[12].r = SUB32_ovflw(S_MUL(scratch[9].i,ya.i), S_MUL(scratch[10].i,yb.i));
|
||||
scratch[12].i = SUB32_ovflw(S_MUL(scratch[10].r,yb.i), S_MUL(scratch[9].r,ya.i));
|
||||
|
||||
C_ADD(*Fout2,scratch[11],scratch[12]);
|
||||
C_SUB(*Fout3,scratch[11],scratch[12]);
|
||||
|
|
|
@ -38,7 +38,8 @@
|
|||
#include "mathops.h"
|
||||
|
||||
/*Compute floor(sqrt(_val)) with exact arithmetic.
|
||||
This has been tested on all possible 32-bit inputs.*/
|
||||
_val must be greater than 0.
|
||||
This has been tested on all possible 32-bit inputs greater than 0.*/
|
||||
unsigned isqrt32(opus_uint32 _val){
|
||||
unsigned b;
|
||||
unsigned g;
|
||||
|
@ -182,7 +183,7 @@ opus_val32 celt_rcp(opus_val32 x)
|
|||
int i;
|
||||
opus_val16 n;
|
||||
opus_val16 r;
|
||||
celt_assert2(x>0, "celt_rcp() only defined for positive values");
|
||||
celt_sig_assert(x>0);
|
||||
i = celt_ilog2(x);
|
||||
/* n is Q15 with range [0,1). */
|
||||
n = VSHR32(x,i-15)-32768;
|
||||
|
|
|
@ -38,11 +38,44 @@
|
|||
#include "entcode.h"
|
||||
#include "os_support.h"
|
||||
|
||||
#define PI 3.141592653f
|
||||
|
||||
/* Multiplies two 16-bit fractional values. Bit-exactness of this macro is important */
|
||||
#define FRAC_MUL16(a,b) ((16384+((opus_int32)(opus_int16)(a)*(opus_int16)(b)))>>15)
|
||||
|
||||
unsigned isqrt32(opus_uint32 _val);
|
||||
|
||||
/* CELT doesn't need it for fixed-point, by analysis.c does. */
|
||||
#if !defined(FIXED_POINT) || defined(ANALYSIS_C)
|
||||
#define cA 0.43157974f
|
||||
#define cB 0.67848403f
|
||||
#define cC 0.08595542f
|
||||
#define cE ((float)PI/2)
|
||||
static OPUS_INLINE float fast_atan2f(float y, float x) {
|
||||
float x2, y2;
|
||||
x2 = x*x;
|
||||
y2 = y*y;
|
||||
/* For very small values, we don't care about the answer, so
|
||||
we can just return 0. */
|
||||
if (x2 + y2 < 1e-18f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if(x2<y2){
|
||||
float den = (y2 + cB*x2) * (y2 + cC*x2);
|
||||
return -x*y*(y2 + cA*x2) / den + (y<0 ? -cE : cE);
|
||||
}else{
|
||||
float den = (x2 + cB*y2) * (x2 + cC*y2);
|
||||
return x*y*(x2 + cA*y2) / den + (y<0 ? -cE : cE) - (x*y<0 ? -cE : cE);
|
||||
}
|
||||
}
|
||||
#undef cA
|
||||
#undef cB
|
||||
#undef cC
|
||||
#undef cE
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef OVERRIDE_CELT_MAXABS16
|
||||
static OPUS_INLINE opus_val32 celt_maxabs16(const opus_val16 *x, int len)
|
||||
{
|
||||
|
@ -80,7 +113,6 @@ static OPUS_INLINE opus_val32 celt_maxabs32(const opus_val32 *x, int len)
|
|||
|
||||
#ifndef FIXED_POINT
|
||||
|
||||
#define PI 3.141592653f
|
||||
#define celt_sqrt(x) ((float)sqrt(x))
|
||||
#define celt_rsqrt(x) (1.f/celt_sqrt(x))
|
||||
#define celt_rsqrt_norm(x) (celt_rsqrt(x))
|
||||
|
@ -147,7 +179,7 @@ static OPUS_INLINE float celt_exp2(float x)
|
|||
/** Integer log in base2. Undefined for zero and negative numbers */
|
||||
static OPUS_INLINE opus_int16 celt_ilog2(opus_int32 x)
|
||||
{
|
||||
celt_assert2(x>0, "celt_ilog2() only defined for strictly positive numbers");
|
||||
celt_sig_assert(x>0);
|
||||
return EC_ILOG(x)-1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -270,8 +270,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca
|
|||
int rev;
|
||||
kiss_fft_scalar yr, yi;
|
||||
rev = *bitrev++;
|
||||
yr = S_MUL(*xp2, t[i]) + S_MUL(*xp1, t[N4+i]);
|
||||
yi = S_MUL(*xp1, t[i]) - S_MUL(*xp2, t[N4+i]);
|
||||
yr = ADD32_ovflw(S_MUL(*xp2, t[i]), S_MUL(*xp1, t[N4+i]));
|
||||
yi = SUB32_ovflw(S_MUL(*xp1, t[i]), S_MUL(*xp2, t[N4+i]));
|
||||
/* We swap real and imag because we use an FFT instead of an IFFT. */
|
||||
yp[2*rev+1] = yr;
|
||||
yp[2*rev] = yi;
|
||||
|
@ -301,8 +301,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca
|
|||
t0 = t[i];
|
||||
t1 = t[N4+i];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = S_MUL(re,t0) + S_MUL(im,t1);
|
||||
yi = S_MUL(re,t1) - S_MUL(im,t0);
|
||||
yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1));
|
||||
yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0));
|
||||
/* We swap real and imag because we're using an FFT instead of an IFFT. */
|
||||
re = yp1[1];
|
||||
im = yp1[0];
|
||||
|
@ -312,8 +312,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca
|
|||
t0 = t[(N4-i-1)];
|
||||
t1 = t[(N2-i-1)];
|
||||
/* We'd scale up by 2 here, but instead it's done when mixing the windows */
|
||||
yr = S_MUL(re,t0) + S_MUL(im,t1);
|
||||
yi = S_MUL(re,t1) - S_MUL(im,t0);
|
||||
yr = ADD32_ovflw(S_MUL(re,t0), S_MUL(im,t1));
|
||||
yi = SUB32_ovflw(S_MUL(re,t1), S_MUL(im,t0));
|
||||
yp1[0] = yr;
|
||||
yp0[1] = yi;
|
||||
yp0 += 2;
|
||||
|
@ -333,8 +333,8 @@ void clt_mdct_backward_c(const mdct_lookup *l, kiss_fft_scalar *in, kiss_fft_sca
|
|||
kiss_fft_scalar x1, x2;
|
||||
x1 = *xp1;
|
||||
x2 = *yp1;
|
||||
*yp1++ = MULT16_32_Q15(*wp2, x2) - MULT16_32_Q15(*wp1, x1);
|
||||
*xp1-- = MULT16_32_Q15(*wp1, x2) + MULT16_32_Q15(*wp2, x1);
|
||||
*yp1++ = SUB32_ovflw(MULT16_32_Q15(*wp2, x2), MULT16_32_Q15(*wp1, x1));
|
||||
*xp1-- = ADD32_ovflw(MULT16_32_Q15(*wp1, x2), MULT16_32_Q15(*wp2, x1));
|
||||
wp1++;
|
||||
wp2--;
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "celt_lpc.h"
|
||||
#include "vq.h"
|
||||
|
||||
#define OVERRIDE_COMB_FILTER_CONST
|
||||
#define OVERRIDE_comb_filter
|
||||
void comb_filter(opus_val32 *y, opus_val32 *x, int T0, int T1, int N,
|
||||
opus_val16 g0, opus_val16 g1, int tapset0, int tapset1,
|
||||
|
|
|
@ -36,11 +36,6 @@
|
|||
#include "mathops.h"
|
||||
#include "arch.h"
|
||||
|
||||
static unsigned extract_collapse_mask(int *iy, int N, int B);
|
||||
static void normalise_residual(int * OPUS_RESTRICT iy, celt_norm * OPUS_RESTRICT X, int N, opus_val32 Ryy, opus_val16 gain);
|
||||
static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread);
|
||||
static void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch);
|
||||
|
||||
#define OVERRIDE_vq_exp_rotation1
|
||||
static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
|
||||
{
|
||||
|
@ -69,11 +64,7 @@ static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_
|
|||
}
|
||||
|
||||
#define OVERRIDE_renormalise_vector
|
||||
|
||||
#define renormalise_vector(X, N, gain, arch) \
|
||||
(renormalise_vector_mips(X, N, gain, arch))
|
||||
|
||||
void renormalise_vector_mips(celt_norm *X, int N, opus_val16 gain, int arch)
|
||||
void renormalise_vector(celt_norm *X, int N, opus_val16 gain, int arch)
|
||||
{
|
||||
int i;
|
||||
#ifdef FIXED_POINT
|
||||
|
|
|
@ -427,7 +427,7 @@ void opus_custom_mode_destroy(CELTMode *mode)
|
|||
}
|
||||
#endif /* CUSTOM_MODES_ONLY */
|
||||
opus_free((opus_int16*)mode->eBands);
|
||||
opus_free((opus_int16*)mode->allocVectors);
|
||||
opus_free((unsigned char*)mode->allocVectors);
|
||||
|
||||
opus_free((opus_val16*)mode->window);
|
||||
opus_free((opus_int16*)mode->logN);
|
||||
|
|
|
@ -102,11 +102,9 @@ static void find_best_pitch(opus_val32 *xcorr, opus_val16 *y, int len,
|
|||
}
|
||||
}
|
||||
|
||||
static void celt_fir5(const opus_val16 *x,
|
||||
static void celt_fir5(opus_val16 *x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *y,
|
||||
int N,
|
||||
opus_val16 *mem)
|
||||
int N)
|
||||
{
|
||||
int i;
|
||||
opus_val16 num0, num1, num2, num3, num4;
|
||||
|
@ -116,11 +114,11 @@ static void celt_fir5(const opus_val16 *x,
|
|||
num2=num[2];
|
||||
num3=num[3];
|
||||
num4=num[4];
|
||||
mem0=mem[0];
|
||||
mem1=mem[1];
|
||||
mem2=mem[2];
|
||||
mem3=mem[3];
|
||||
mem4=mem[4];
|
||||
mem0=0;
|
||||
mem1=0;
|
||||
mem2=0;
|
||||
mem3=0;
|
||||
mem4=0;
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = SHL32(EXTEND32(x[i]), SIG_SHIFT);
|
||||
|
@ -134,13 +132,8 @@ static void celt_fir5(const opus_val16 *x,
|
|||
mem2 = mem1;
|
||||
mem1 = mem0;
|
||||
mem0 = x[i];
|
||||
y[i] = ROUND16(sum, SIG_SHIFT);
|
||||
x[i] = ROUND16(sum, SIG_SHIFT);
|
||||
}
|
||||
mem[0]=mem0;
|
||||
mem[1]=mem1;
|
||||
mem[2]=mem2;
|
||||
mem[3]=mem3;
|
||||
mem[4]=mem4;
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,7 +143,7 @@ void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x
|
|||
int i;
|
||||
opus_val32 ac[5];
|
||||
opus_val16 tmp=Q15ONE;
|
||||
opus_val16 lpc[4], mem[5]={0,0,0,0,0};
|
||||
opus_val16 lpc[4];
|
||||
opus_val16 lpc2[5];
|
||||
opus_val16 c1 = QCONST16(.8f,15);
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -211,7 +204,7 @@ void pitch_downsample(celt_sig * OPUS_RESTRICT x[], opus_val16 * OPUS_RESTRICT x
|
|||
lpc2[2] = lpc[2] + MULT16_16_Q15(c1,lpc[1]);
|
||||
lpc2[3] = lpc[3] + MULT16_16_Q15(c1,lpc[2]);
|
||||
lpc2[4] = MULT16_16_Q15(c1,lpc[3]);
|
||||
celt_fir5(x_lp, lpc2, x_lp, len>>1, mem);
|
||||
celt_fir5(x_lp, lpc2, len>>1);
|
||||
}
|
||||
|
||||
/* Pure C implementation. */
|
||||
|
@ -220,13 +213,8 @@ opus_val32
|
|||
#else
|
||||
void
|
||||
#endif
|
||||
#if defined(OVERRIDE_PITCH_XCORR)
|
||||
celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch)
|
||||
#else
|
||||
celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch)
|
||||
#endif
|
||||
{
|
||||
|
||||
#if 0 /* This is a simple version of the pitch correlation that should work
|
||||
|
@ -261,15 +249,11 @@ celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
|||
opus_val32 maxcorr=1;
|
||||
#endif
|
||||
celt_assert(max_pitch>0);
|
||||
celt_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||
celt_sig_assert((((unsigned char *)_x-(unsigned char *)NULL)&3)==0);
|
||||
for (i=0;i<max_pitch-3;i+=4)
|
||||
{
|
||||
opus_val32 sum[4]={0,0,0,0};
|
||||
#if defined(OVERRIDE_PITCH_XCORR)
|
||||
xcorr_kernel_c(_x, _y+i, sum, len);
|
||||
#else
|
||||
xcorr_kernel(_x, _y+i, sum, len, arch);
|
||||
#endif
|
||||
xcorr[i]=sum[0];
|
||||
xcorr[i+1]=sum[1];
|
||||
xcorr[i+2]=sum[2];
|
||||
|
@ -285,11 +269,7 @@ celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
|||
for (;i<max_pitch;i++)
|
||||
{
|
||||
opus_val32 sum;
|
||||
#if defined(OVERRIDE_PITCH_XCORR)
|
||||
sum = celt_inner_prod_c(_x, _y+i, len);
|
||||
#else
|
||||
sum = celt_inner_prod(_x, _y+i, len, arch);
|
||||
#endif
|
||||
xcorr[i] = sum;
|
||||
#ifdef FIXED_POINT
|
||||
maxcorr = MAX32(maxcorr, sum);
|
||||
|
@ -378,7 +358,7 @@ void pitch_search(const opus_val16 * OPUS_RESTRICT x_lp, opus_val16 * OPUS_RESTR
|
|||
for (j=0;j<len>>1;j++)
|
||||
sum += SHR32(MULT16_16(x_lp[j],y[i+j]), shift);
|
||||
#else
|
||||
sum = celt_inner_prod_c(x_lp, y+i, len>>1);
|
||||
sum = celt_inner_prod(x_lp, y+i, len>>1, arch);
|
||||
#endif
|
||||
xcorr[i] = MAX32(-1, sum);
|
||||
#ifdef FIXED_POINT
|
||||
|
@ -424,7 +404,7 @@ static opus_val16 compute_pitch_gain(opus_val32 xy, opus_val32 xx, opus_val32 yy
|
|||
sx = celt_ilog2(xx)-14;
|
||||
sy = celt_ilog2(yy)-14;
|
||||
shift = sx + sy;
|
||||
x2y2 = MULT16_16_Q14(VSHR32(xx, sx), VSHR32(yy, sy));
|
||||
x2y2 = SHR32(MULT16_16(VSHR32(xx, sx), VSHR32(yy, sy)), 14);
|
||||
if (shift & 1) {
|
||||
if (x2y2 < 32768)
|
||||
{
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
#include "mips/pitch_mipsr1.h"
|
||||
#endif
|
||||
|
||||
#if ((defined(OPUS_ARM_ASM) && defined(FIXED_POINT)) \
|
||||
|| defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
|
||||
#if (defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR))
|
||||
# include "arm/pitch_arm.h"
|
||||
#endif
|
||||
|
||||
|
@ -184,17 +183,10 @@ opus_val32
|
|||
void
|
||||
#endif
|
||||
celt_pitch_xcorr_c(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch);
|
||||
|
||||
#if !defined(OVERRIDE_PITCH_XCORR)
|
||||
#ifdef FIXED_POINT
|
||||
opus_val32
|
||||
#else
|
||||
void
|
||||
#endif
|
||||
celt_pitch_xcorr(const opus_val16 *_x, const opus_val16 *_y,
|
||||
opus_val32 *xcorr, int len, int max_pitch, int arch);
|
||||
|
||||
#ifndef OVERRIDE_PITCH_XCORR
|
||||
# define celt_pitch_xcorr celt_pitch_xcorr_c
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -418,6 +418,7 @@ void quant_energy_finalise(const CELTMode *m, int start, int end, opus_val16 *ol
|
|||
offset = (q2-.5f)*(1<<(14-fine_quant[i]-1))*(1.f/16384);
|
||||
#endif
|
||||
oldEBands[i+c*m->nbEBands] += offset;
|
||||
error[i+c*m->nbEBands] -= offset;
|
||||
bits_left--;
|
||||
} while (++c < C);
|
||||
}
|
||||
|
@ -456,7 +457,7 @@ void unquant_coarse_energy(const CELTMode *m, int start, int end, opus_val16 *ol
|
|||
/* It would be better to express this invariant as a
|
||||
test on C at function entry, but that isn't enough
|
||||
to make the static analyzer happy. */
|
||||
celt_assert(c<2);
|
||||
celt_sig_assert(c<2);
|
||||
tell = ec_tell(dec);
|
||||
if(budget-tell>=15)
|
||||
{
|
||||
|
@ -547,9 +548,15 @@ void amp2Log2(const CELTMode *m, int effEnd, int end,
|
|||
c=0;
|
||||
do {
|
||||
for (i=0;i<effEnd;i++)
|
||||
{
|
||||
bandLogE[i+c*m->nbEBands] =
|
||||
celt_log2(SHL32(bandE[i+c*m->nbEBands],2))
|
||||
celt_log2(bandE[i+c*m->nbEBands])
|
||||
- SHL16((opus_val16)eMeans[i],6);
|
||||
#ifdef FIXED_POINT
|
||||
/* Compensate for bandE[] being Q12 but celt_log2() taking a Q14 input. */
|
||||
bandLogE[i+c*m->nbEBands] += QCONST16(2.f, DB_SHIFT);
|
||||
#endif
|
||||
}
|
||||
for (i=effEnd;i<end;i++)
|
||||
bandLogE[c*m->nbEBands+i] = -QCONST16(14.f,DB_SHIFT);
|
||||
} while (++c < C);
|
||||
|
|
|
@ -348,12 +348,17 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end,
|
|||
/*This if() block is the only part of the allocation function that
|
||||
is not a mandatory part of the bitstream: any bands we choose to
|
||||
skip here must be explicitly signaled.*/
|
||||
/*Choose a threshold with some hysteresis to keep bands from
|
||||
fluctuating in and out.*/
|
||||
int depth_threshold;
|
||||
/*We choose a threshold with some hysteresis to keep bands from
|
||||
fluctuating in and out, but we try not to fold below a certain point. */
|
||||
if (codedBands > 17)
|
||||
depth_threshold = j<prev ? 7 : 9;
|
||||
else
|
||||
depth_threshold = 0;
|
||||
#ifdef FUZZING
|
||||
if ((rand()&0x1) == 0)
|
||||
#else
|
||||
if (codedBands<=start+2 || (band_bits > ((j<prev?7:9)*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
|
||||
if (codedBands<=start+2 || (band_bits > (depth_threshold*band_width<<LM<<BITRES)>>4 && j<=signalBandwidth))
|
||||
#endif
|
||||
{
|
||||
ec_enc_bit_logp(ec, 1, 1);
|
||||
|
@ -524,7 +529,7 @@ static OPUS_INLINE int interp_bits2pulses(const CELTMode *m, int start, int end,
|
|||
return codedBands;
|
||||
}
|
||||
|
||||
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
|
||||
int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
|
||||
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth)
|
||||
{
|
||||
int lo, hi, len, j;
|
||||
|
|
|
@ -95,7 +95,7 @@ static OPUS_INLINE int pulses2bits(const CELTMode *m, int band, int LM, int puls
|
|||
@param pulses Number of pulses per band (returned)
|
||||
@return Total number of bits allocated
|
||||
*/
|
||||
int compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stero,
|
||||
int clt_compute_allocation(const CELTMode *m, int start, int end, const int *offsets, const int *cap, int alloc_trim, int *intensity, int *dual_stereo,
|
||||
opus_int32 total, opus_int32 *balance, int *pulses, int *ebits, int *fine_priority, int C, int LM, ec_ctx *ec, int encode, int prev, int signalBandwidth);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* The contents of this file was automatically generated by
|
||||
* dump_mode_arm_ne10.c with arguments: 48000 960
|
||||
* It contains static definitions for some pre-defined modes. */
|
||||
#include <NE10_init.h>
|
||||
#include <NE10_types.h>
|
||||
|
||||
#ifndef NE10_FFT_PARAMS48000_960
|
||||
#define NE10_FFT_PARAMS48000_960
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* The contents of this file was automatically generated by
|
||||
* dump_mode_arm_ne10.c with arguments: 48000 960
|
||||
* It contains static definitions for some pre-defined modes. */
|
||||
#include <NE10_init.h>
|
||||
#include <NE10_types.h>
|
||||
|
||||
#ifndef NE10_FFT_PARAMS48000_960
|
||||
#define NE10_FFT_PARAMS48000_960
|
||||
|
|
|
@ -1,161 +0,0 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#else
|
||||
#define TEST_CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
#include "stack_alloc.h"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "cwrs.c"
|
||||
#include "mathops.c"
|
||||
#include "rate.h"
|
||||
|
||||
#define NMAX (240)
|
||||
#define KMAX (128)
|
||||
|
||||
#ifdef TEST_CUSTOM_MODES
|
||||
|
||||
#define NDIMS (44)
|
||||
static const int pn[NDIMS]={
|
||||
2, 3, 4, 5, 6, 7, 8, 9, 10,
|
||||
11, 12, 13, 14, 15, 16, 18, 20, 22,
|
||||
24, 26, 28, 30, 32, 36, 40, 44, 48,
|
||||
52, 56, 60, 64, 72, 80, 88, 96, 104,
|
||||
112, 120, 128, 144, 160, 176, 192, 208
|
||||
};
|
||||
static const int pkmax[NDIMS]={
|
||||
128, 128, 128, 128, 88, 52, 36, 26, 22,
|
||||
18, 16, 15, 13, 12, 12, 11, 10, 9,
|
||||
9, 8, 8, 7, 7, 7, 7, 6, 6,
|
||||
6, 6, 6, 5, 5, 5, 5, 5, 5,
|
||||
4, 4, 4, 4, 4, 4, 4, 4
|
||||
};
|
||||
|
||||
#else /* TEST_CUSTOM_MODES */
|
||||
|
||||
#define NDIMS (22)
|
||||
static const int pn[NDIMS]={
|
||||
2, 3, 4, 6, 8, 9, 11, 12, 16,
|
||||
18, 22, 24, 32, 36, 44, 48, 64, 72,
|
||||
88, 96, 144, 176
|
||||
};
|
||||
static const int pkmax[NDIMS]={
|
||||
128, 128, 128, 88, 36, 26, 18, 16, 12,
|
||||
11, 9, 9, 7, 7, 6, 6, 5, 5,
|
||||
5, 5, 4, 4
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
int main(void){
|
||||
int t;
|
||||
int n;
|
||||
ALLOC_STACK;
|
||||
for(t=0;t<NDIMS;t++){
|
||||
int pseudo;
|
||||
n=pn[t];
|
||||
for(pseudo=1;pseudo<41;pseudo++)
|
||||
{
|
||||
int k;
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
opus_uint32 uu[KMAX+2U];
|
||||
#endif
|
||||
opus_uint32 inc;
|
||||
opus_uint32 nc;
|
||||
opus_uint32 i;
|
||||
k=get_pulses(pseudo);
|
||||
if (k>pkmax[t])break;
|
||||
printf("Testing CWRS with N=%i, K=%i...\n",n,k);
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
nc=ncwrs_urow(n,k,uu);
|
||||
#else
|
||||
nc=CELT_PVQ_V(n,k);
|
||||
#endif
|
||||
inc=nc/20000;
|
||||
if(inc<1)inc=1;
|
||||
for(i=0;i<nc;i+=inc){
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
opus_uint32 u[KMAX+2U];
|
||||
#endif
|
||||
int y[NMAX];
|
||||
int sy;
|
||||
opus_uint32 v;
|
||||
opus_uint32 ii;
|
||||
int j;
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
memcpy(u,uu,(k+2U)*sizeof(*u));
|
||||
cwrsi(n,k,i,y,u);
|
||||
#else
|
||||
cwrsi(n,k,i,y);
|
||||
#endif
|
||||
sy=0;
|
||||
for(j=0;j<n;j++)sy+=abs(y[j]);
|
||||
if(sy!=k){
|
||||
fprintf(stderr,"N=%d Pulse count mismatch in cwrsi (%d!=%d).\n",
|
||||
n,sy,k);
|
||||
return 99;
|
||||
}
|
||||
/*printf("%6u of %u:",i,nc);
|
||||
for(j=0;j<n;j++)printf(" %+3i",y[j]);
|
||||
printf(" ->");*/
|
||||
#if defined(SMALL_FOOTPRINT)
|
||||
ii=icwrs(n,k,&v,y,u);
|
||||
#else
|
||||
ii=icwrs(n,y);
|
||||
v=CELT_PVQ_V(n,k);
|
||||
#endif
|
||||
if(ii!=i){
|
||||
fprintf(stderr,"Combination-index mismatch (%lu!=%lu).\n",
|
||||
(long)ii,(long)i);
|
||||
return 1;
|
||||
}
|
||||
if(v!=nc){
|
||||
fprintf(stderr,"Combination count mismatch (%lu!=%lu).\n",
|
||||
(long)v,(long)nc);
|
||||
return 2;
|
||||
}
|
||||
/*printf(" %6u\n",i);*/
|
||||
}
|
||||
/*printf("\n");*/
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
/* Copyright (c) 2008 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define SKIP_CONFIG_H
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define CELT_C
|
||||
#define TEST_UNIT_DFT_C
|
||||
#include "stack_alloc.h"
|
||||
#include "kiss_fft.h"
|
||||
#include "kiss_fft.c"
|
||||
#include "mathops.c"
|
||||
#include "entcode.c"
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# include "x86/x86cpu.c"
|
||||
#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/armcpu.c"
|
||||
# include "celt_lpc.c"
|
||||
# include "pitch.c"
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/celt_neon_intr.c"
|
||||
# if defined(HAVE_ARM_NE10)
|
||||
# include "mdct.c"
|
||||
# include "arm/celt_ne10_fft.c"
|
||||
# include "arm/celt_ne10_mdct.c"
|
||||
# endif
|
||||
# endif
|
||||
# include "arm/arm_celt_map.c"
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
void check(kiss_fft_cpx * in,kiss_fft_cpx * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0, snr;
|
||||
|
||||
for (bin=0;bin<nfft;++bin) {
|
||||
double ansr = 0;
|
||||
double ansi = 0;
|
||||
double difr;
|
||||
double difi;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
double phase = -2*M_PI*bin*k/nfft;
|
||||
double re = cos(phase);
|
||||
double im = sin(phase);
|
||||
if (isinverse)
|
||||
im = -im;
|
||||
|
||||
if (!isinverse)
|
||||
{
|
||||
re /= nfft;
|
||||
im /= nfft;
|
||||
}
|
||||
|
||||
ansr += in[k].r * re - in[k].i * im;
|
||||
ansi += in[k].r * im + in[k].i * re;
|
||||
}
|
||||
/*printf ("%d %d ", (int)ansr, (int)ansi);*/
|
||||
difr = ansr - out[bin].r;
|
||||
difi = ansi - out[bin].i;
|
||||
errpow += difr*difr + difi*difi;
|
||||
sigpow += ansr*ansr+ansi*ansi;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f ** \n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void test1d(int nfft,int isinverse,int arch)
|
||||
{
|
||||
size_t buflen = sizeof(kiss_fft_cpx)*nfft;
|
||||
|
||||
kiss_fft_cpx * in = (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_cpx * out= (kiss_fft_cpx*)malloc(buflen);
|
||||
kiss_fft_state *cfg = opus_fft_alloc(nfft,0,0,arch);
|
||||
int k;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r = (rand() % 32767) - 16384;
|
||||
in[k].i = (rand() % 32767) - 16384;
|
||||
}
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r *= 32768;
|
||||
in[k].i *= 32768;
|
||||
}
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k].r /= nfft;
|
||||
in[k].i /= nfft;
|
||||
}
|
||||
}
|
||||
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
|
||||
|
||||
if (isinverse)
|
||||
opus_ifft(cfg,in,out, arch);
|
||||
else
|
||||
opus_fft(cfg,in,out, arch);
|
||||
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
|
||||
|
||||
check(in,out,nfft,isinverse);
|
||||
|
||||
free(in);
|
||||
free(out);
|
||||
opus_fft_free(cfg, arch);
|
||||
}
|
||||
|
||||
int main(int argc,char ** argv)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
int arch = opus_select_arch();
|
||||
|
||||
if (argc>1) {
|
||||
int k;
|
||||
for (k=1;k<argc;++k) {
|
||||
test1d(atoi(argv[k]),0,arch);
|
||||
test1d(atoi(argv[k]),1,arch);
|
||||
}
|
||||
}else{
|
||||
test1d(32,0,arch);
|
||||
test1d(32,1,arch);
|
||||
test1d(128,0,arch);
|
||||
test1d(128,1,arch);
|
||||
test1d(256,0,arch);
|
||||
test1d(256,1,arch);
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
test1d(36,0,arch);
|
||||
test1d(36,1,arch);
|
||||
test1d(50,0,arch);
|
||||
test1d(50,1,arch);
|
||||
test1d(60,0,arch);
|
||||
test1d(60,1,arch);
|
||||
test1d(120,0,arch);
|
||||
test1d(120,1,arch);
|
||||
test1d(240,0,arch);
|
||||
test1d(240,1,arch);
|
||||
test1d(480,0,arch);
|
||||
test1d(480,1,arch);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -1,382 +0,0 @@
|
|||
/* Copyright (c) 2007-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <time.h>
|
||||
#include "entcode.h"
|
||||
#include "entenc.h"
|
||||
#include "entdec.h"
|
||||
#include <string.h>
|
||||
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
|
||||
#ifndef M_LOG2E
|
||||
# define M_LOG2E 1.4426950408889634074
|
||||
#endif
|
||||
#define DATA_SIZE 10000000
|
||||
#define DATA_SIZE2 10000
|
||||
|
||||
int main(int _argc,char **_argv){
|
||||
ec_enc enc;
|
||||
ec_dec dec;
|
||||
long nbits;
|
||||
long nbits2;
|
||||
double entropy;
|
||||
int ft;
|
||||
int ftb;
|
||||
int sz;
|
||||
int i;
|
||||
int ret;
|
||||
unsigned int sym;
|
||||
unsigned int seed;
|
||||
unsigned char *ptr;
|
||||
const char *env_seed;
|
||||
ret=0;
|
||||
entropy=0;
|
||||
if (_argc > 2) {
|
||||
fprintf(stderr, "Usage: %s [<seed>]\n", _argv[0]);
|
||||
return 1;
|
||||
}
|
||||
env_seed = getenv("SEED");
|
||||
if (_argc > 1)
|
||||
seed = atoi(_argv[1]);
|
||||
else if (env_seed)
|
||||
seed = atoi(env_seed);
|
||||
else
|
||||
seed = time(NULL);
|
||||
/*Testing encoding of raw bit values.*/
|
||||
ptr = (unsigned char *)malloc(DATA_SIZE);
|
||||
ec_enc_init(&enc,ptr, DATA_SIZE);
|
||||
for(ft=2;ft<1024;ft++){
|
||||
for(i=0;i<ft;i++){
|
||||
entropy+=log(ft)*M_LOG2E;
|
||||
ec_enc_uint(&enc,i,ft);
|
||||
}
|
||||
}
|
||||
/*Testing encoding of raw bit values.*/
|
||||
for(ftb=1;ftb<16;ftb++){
|
||||
for(i=0;i<(1<<ftb);i++){
|
||||
entropy+=ftb;
|
||||
nbits=ec_tell(&enc);
|
||||
ec_enc_bits(&enc,i,ftb);
|
||||
nbits2=ec_tell(&enc);
|
||||
if(nbits2-nbits!=ftb){
|
||||
fprintf(stderr,"Used %li bits to encode %i bits directly.\n",
|
||||
nbits2-nbits,ftb);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
nbits=ec_tell_frac(&enc);
|
||||
ec_enc_done(&enc);
|
||||
fprintf(stderr,
|
||||
"Encoded %0.2lf bits of entropy to %0.2lf bits (%0.3lf%% wasted).\n",
|
||||
entropy,ldexp(nbits,-3),100*(nbits-ldexp(entropy,3))/nbits);
|
||||
fprintf(stderr,"Packed to %li bytes.\n",(long)ec_range_bytes(&enc));
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE);
|
||||
for(ft=2;ft<1024;ft++){
|
||||
for(i=0;i<ft;i++){
|
||||
sym=ec_dec_uint(&dec,ft);
|
||||
if(sym!=(unsigned)i){
|
||||
fprintf(stderr,"Decoded %i instead of %i with ft of %i.\n",sym,i,ft);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(ftb=1;ftb<16;ftb++){
|
||||
for(i=0;i<(1<<ftb);i++){
|
||||
sym=ec_dec_bits(&dec,ftb);
|
||||
if(sym!=(unsigned)i){
|
||||
fprintf(stderr,"Decoded %i instead of %i with ftb of %i.\n",sym,i,ftb);
|
||||
ret=-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
nbits2=ec_tell_frac(&dec);
|
||||
if(nbits!=nbits2){
|
||||
fprintf(stderr,
|
||||
"Reported number of bits used was %0.2lf, should be %0.2lf.\n",
|
||||
ldexp(nbits2,-3),ldexp(nbits,-3));
|
||||
ret=-1;
|
||||
}
|
||||
/*Testing an encoder bust prefers range coder data over raw bits.
|
||||
This isn't a general guarantee, will only work for data that is buffered in
|
||||
the encoder state and not yet stored in the user buffer, and should never
|
||||
get used in practice.
|
||||
It's mostly here for code coverage completeness.*/
|
||||
/*Start with a 16-bit buffer.*/
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
/*Write 7 raw bits.*/
|
||||
ec_enc_bits(&enc,0x55,7);
|
||||
/*Write 12.3 bits of range coder data.*/
|
||||
ec_enc_uint(&enc,1,2);
|
||||
ec_enc_uint(&enc,1,3);
|
||||
ec_enc_uint(&enc,1,4);
|
||||
ec_enc_uint(&enc,1,5);
|
||||
ec_enc_uint(&enc,2,6);
|
||||
ec_enc_uint(&enc,6,7);
|
||||
ec_enc_done(&enc);
|
||||
ec_dec_init(&dec,ptr,2);
|
||||
if(!enc.error
|
||||
/*The raw bits should have been overwritten by the range coder data.*/
|
||||
||ec_dec_bits(&dec,7)!=0x05
|
||||
/*And all the range coder data should have been encoded correctly.*/
|
||||
||ec_dec_uint(&dec,2)!=1
|
||||
||ec_dec_uint(&dec,3)!=1
|
||||
||ec_dec_uint(&dec,4)!=1
|
||||
||ec_dec_uint(&dec,5)!=1
|
||||
||ec_dec_uint(&dec,6)!=2
|
||||
||ec_dec_uint(&dec,7)!=6){
|
||||
fprintf(stderr,"Encoder bust overwrote range coder data with raw bits.\n");
|
||||
ret=-1;
|
||||
}
|
||||
srand(seed);
|
||||
fprintf(stderr,"Testing random streams... Random seed: %u (%.4X)\n", seed, rand() % 65536);
|
||||
for(i=0;i<409600;i++){
|
||||
unsigned *data;
|
||||
unsigned *tell;
|
||||
unsigned tell_bits;
|
||||
int j;
|
||||
int zeros;
|
||||
ft=rand()/((RAND_MAX>>(rand()%11U))+1U)+10;
|
||||
sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
|
||||
data=(unsigned *)malloc(sz*sizeof(*data));
|
||||
tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
zeros = rand()%13==0;
|
||||
tell[0]=ec_tell_frac(&enc);
|
||||
for(j=0;j<sz;j++){
|
||||
if (zeros)
|
||||
data[j]=0;
|
||||
else
|
||||
data[j]=rand()%ft;
|
||||
ec_enc_uint(&enc,data[j],ft);
|
||||
tell[j+1]=ec_tell_frac(&enc);
|
||||
}
|
||||
if (rand()%2==0)
|
||||
while(ec_tell(&enc)%8 != 0)
|
||||
ec_enc_uint(&enc, rand()%2, 2);
|
||||
tell_bits = ec_tell(&enc);
|
||||
ec_enc_done(&enc);
|
||||
if(tell_bits!=(unsigned)ec_tell(&enc)){
|
||||
fprintf(stderr,"ec_tell() changed after ec_enc_done(): %i instead of %i (Random seed: %u)\n",
|
||||
ec_tell(&enc),tell_bits,seed);
|
||||
ret=-1;
|
||||
}
|
||||
if ((tell_bits+7)/8 < ec_range_bytes(&enc))
|
||||
{
|
||||
fprintf (stderr, "ec_tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
|
||||
ec_range_bytes(&enc), (tell_bits+7)/8,seed);
|
||||
ret=-1;
|
||||
}
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE2);
|
||||
if(ec_tell_frac(&dec)!=tell[0]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
0,ec_tell_frac(&dec),tell[0],seed);
|
||||
}
|
||||
for(j=0;j<sz;j++){
|
||||
sym=ec_dec_uint(&dec,ft);
|
||||
if(sym!=data[j]){
|
||||
fprintf(stderr,
|
||||
"Decoded %i instead of %i with ft of %i at position %i of %i (Random seed: %u).\n",
|
||||
sym,data[j],ft,j,sz,seed);
|
||||
ret=-1;
|
||||
}
|
||||
if(ec_tell_frac(&dec)!=tell[j+1]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
j+1,ec_tell_frac(&dec),tell[j+1],seed);
|
||||
}
|
||||
}
|
||||
free(tell);
|
||||
free(data);
|
||||
}
|
||||
/*Test compatibility between multiple different encode/decode routines.*/
|
||||
for(i=0;i<409600;i++){
|
||||
unsigned *logp1;
|
||||
unsigned *data;
|
||||
unsigned *tell;
|
||||
unsigned *enc_method;
|
||||
int j;
|
||||
sz=rand()/((RAND_MAX>>(rand()%9U))+1U);
|
||||
logp1=(unsigned *)malloc(sz*sizeof(*logp1));
|
||||
data=(unsigned *)malloc(sz*sizeof(*data));
|
||||
tell=(unsigned *)malloc((sz+1)*sizeof(*tell));
|
||||
enc_method=(unsigned *)malloc(sz*sizeof(*enc_method));
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
tell[0]=ec_tell_frac(&enc);
|
||||
for(j=0;j<sz;j++){
|
||||
data[j]=rand()/((RAND_MAX>>1)+1);
|
||||
logp1[j]=(rand()%15)+1;
|
||||
enc_method[j]=rand()/((RAND_MAX>>2)+1);
|
||||
switch(enc_method[j]){
|
||||
case 0:{
|
||||
ec_encode(&enc,data[j]?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(data[j]?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 1:{
|
||||
ec_encode_bin(&enc,data[j]?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(data[j]?0:1),logp1[j]);
|
||||
}break;
|
||||
case 2:{
|
||||
ec_enc_bit_logp(&enc,data[j],logp1[j]);
|
||||
}break;
|
||||
case 3:{
|
||||
unsigned char icdf[2];
|
||||
icdf[0]=1;
|
||||
icdf[1]=0;
|
||||
ec_enc_icdf(&enc,data[j],icdf,logp1[j]);
|
||||
}break;
|
||||
}
|
||||
tell[j+1]=ec_tell_frac(&enc);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if((ec_tell(&enc)+7U)/8U<ec_range_bytes(&enc)){
|
||||
fprintf(stderr,"tell() lied, there's %i bytes instead of %d (Random seed: %u)\n",
|
||||
ec_range_bytes(&enc),(ec_tell(&enc)+7)/8,seed);
|
||||
ret=-1;
|
||||
}
|
||||
ec_dec_init(&dec,ptr,DATA_SIZE2);
|
||||
if(ec_tell_frac(&dec)!=tell[0]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
0,ec_tell_frac(&dec),tell[0],seed);
|
||||
}
|
||||
for(j=0;j<sz;j++){
|
||||
int fs;
|
||||
int dec_method;
|
||||
dec_method=rand()/((RAND_MAX>>2)+1);
|
||||
switch(dec_method){
|
||||
case 0:{
|
||||
fs=ec_decode(&dec,1<<logp1[j]);
|
||||
sym=fs>=(1<<logp1[j])-1;
|
||||
ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(sym?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 1:{
|
||||
fs=ec_decode_bin(&dec,logp1[j]);
|
||||
sym=fs>=(1<<logp1[j])-1;
|
||||
ec_dec_update(&dec,sym?(1<<logp1[j])-1:0,
|
||||
(1<<logp1[j])-(sym?0:1),1<<logp1[j]);
|
||||
}break;
|
||||
case 2:{
|
||||
sym=ec_dec_bit_logp(&dec,logp1[j]);
|
||||
}break;
|
||||
case 3:{
|
||||
unsigned char icdf[2];
|
||||
icdf[0]=1;
|
||||
icdf[1]=0;
|
||||
sym=ec_dec_icdf(&dec,icdf,logp1[j]);
|
||||
}break;
|
||||
}
|
||||
if(sym!=data[j]){
|
||||
fprintf(stderr,
|
||||
"Decoded %i instead of %i with logp1 of %i at position %i of %i (Random seed: %u).\n",
|
||||
sym,data[j],logp1[j],j,sz,seed);
|
||||
fprintf(stderr,"Encoding method: %i, decoding method: %i\n",
|
||||
enc_method[j],dec_method);
|
||||
ret=-1;
|
||||
}
|
||||
if(ec_tell_frac(&dec)!=tell[j+1]){
|
||||
fprintf(stderr,
|
||||
"Tell mismatch between encoder and decoder at symbol %i: %i instead of %i (Random seed: %u).\n",
|
||||
j+1,ec_tell_frac(&dec),tell[j+1],seed);
|
||||
}
|
||||
}
|
||||
free(enc_method);
|
||||
free(tell);
|
||||
free(data);
|
||||
free(logp1);
|
||||
}
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
ec_enc_patch_initial_bits(&enc,3,2);
|
||||
if(enc.error){
|
||||
fprintf(stderr,"patch_initial_bits failed");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_patch_initial_bits(&enc,0,5);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"patch_initial_bits didn't fail when it should have");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(ec_range_bytes(&enc)!=1||ptr[0]!=192){
|
||||
fprintf(stderr,"Got %d when expecting 192 for patch_initial_bits",ptr[0]);
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE2);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,0,1);
|
||||
ec_enc_bit_logp(&enc,1,6);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
ec_enc_patch_initial_bits(&enc,0,2);
|
||||
if(enc.error){
|
||||
fprintf(stderr,"patch_initial_bits failed");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(ec_range_bytes(&enc)!=2||ptr[0]!=63){
|
||||
fprintf(stderr,"Got %d when expecting 63 for patch_initial_bits",ptr[0]);
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
ec_enc_bit_logp(&enc,0,2);
|
||||
for(i=0;i<48;i++){
|
||||
ec_enc_bits(&enc,0,1);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"Raw bits overfill didn't fail when it should have");
|
||||
ret=-1;
|
||||
}
|
||||
ec_enc_init(&enc,ptr,2);
|
||||
for(i=0;i<17;i++){
|
||||
ec_enc_bits(&enc,0,1);
|
||||
}
|
||||
ec_enc_done(&enc);
|
||||
if(!enc.error){
|
||||
fprintf(stderr,"17 raw bits encoded in two bytes");
|
||||
ret=-1;
|
||||
}
|
||||
free(ptr);
|
||||
return ret;
|
||||
}
|
|
@ -1,93 +0,0 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation
|
||||
Written by Jean-Marc Valin and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "laplace.h"
|
||||
#define CELT_C
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "laplace.c"
|
||||
|
||||
#define DATA_SIZE 40000
|
||||
|
||||
int ec_laplace_get_start_freq(int decay)
|
||||
{
|
||||
opus_uint32 ft = 32768 - LAPLACE_MINP*(2*LAPLACE_NMIN+1);
|
||||
int fs = (ft*(16384-decay))/(16384+decay);
|
||||
return fs+LAPLACE_MINP;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int i;
|
||||
int ret = 0;
|
||||
ec_enc enc;
|
||||
ec_dec dec;
|
||||
unsigned char *ptr;
|
||||
int val[10000], decay[10000];
|
||||
ALLOC_STACK;
|
||||
ptr = (unsigned char *)malloc(DATA_SIZE);
|
||||
ec_enc_init(&enc,ptr,DATA_SIZE);
|
||||
|
||||
val[0] = 3; decay[0] = 6000;
|
||||
val[1] = 0; decay[1] = 5800;
|
||||
val[2] = -1; decay[2] = 5600;
|
||||
for (i=3;i<10000;i++)
|
||||
{
|
||||
val[i] = rand()%15-7;
|
||||
decay[i] = rand()%11000+5000;
|
||||
}
|
||||
for (i=0;i<10000;i++)
|
||||
ec_laplace_encode(&enc, &val[i],
|
||||
ec_laplace_get_start_freq(decay[i]), decay[i]);
|
||||
|
||||
ec_enc_done(&enc);
|
||||
|
||||
ec_dec_init(&dec,ec_get_buffer(&enc),ec_range_bytes(&enc));
|
||||
|
||||
for (i=0;i<10000;i++)
|
||||
{
|
||||
int d = ec_laplace_decode(&dec,
|
||||
ec_laplace_get_start_freq(decay[i]), decay[i]);
|
||||
if (d != val[i])
|
||||
{
|
||||
fprintf (stderr, "Got %d instead of %d\n", d, val[i]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
free(ptr);
|
||||
return ret;
|
||||
}
|
|
@ -1,304 +0,0 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation, Mozilla Corporation,
|
||||
Gregory Maxwell
|
||||
Written by Jean-Marc Valin, Gregory Maxwell, and Timothy B. Terriberry */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include "mathops.c"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "entcode.c"
|
||||
#include "bands.c"
|
||||
#include "quant_bands.c"
|
||||
#include "laplace.c"
|
||||
#include "vq.c"
|
||||
#include "cwrs.c"
|
||||
#include "pitch.c"
|
||||
#include "celt_lpc.c"
|
||||
#include "celt.c"
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE)
|
||||
# include "x86/pitch_sse.c"
|
||||
# endif
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE2)
|
||||
# include "x86/pitch_sse2.c"
|
||||
# endif
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# include "x86/pitch_sse4_1.c"
|
||||
# include "x86/celt_lpc_sse.c"
|
||||
# endif
|
||||
# include "x86/x86_celt_map.c"
|
||||
#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/armcpu.c"
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/celt_neon_intr.c"
|
||||
# if defined(HAVE_ARM_NE10)
|
||||
# include "kiss_fft.c"
|
||||
# include "mdct.c"
|
||||
# include "arm/celt_ne10_fft.c"
|
||||
# include "arm/celt_ne10_mdct.c"
|
||||
# endif
|
||||
# endif
|
||||
# include "arm/arm_celt_map.c"
|
||||
#endif
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
#define WORD "%d"
|
||||
#else
|
||||
#define WORD "%f"
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
|
||||
void testdiv(void)
|
||||
{
|
||||
opus_int32 i;
|
||||
for (i=1;i<=327670;i++)
|
||||
{
|
||||
double prod;
|
||||
opus_val32 val;
|
||||
val = celt_rcp(i);
|
||||
#ifdef FIXED_POINT
|
||||
prod = (1./32768./65526.)*val*i;
|
||||
#else
|
||||
prod = val*i;
|
||||
#endif
|
||||
if (fabs(prod-1) > .00025)
|
||||
{
|
||||
fprintf (stderr, "div failed: 1/%d="WORD" (product = %f)\n", i, val, prod);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testsqrt(void)
|
||||
{
|
||||
opus_int32 i;
|
||||
for (i=1;i<=1000000000;i++)
|
||||
{
|
||||
double ratio;
|
||||
opus_val16 val;
|
||||
val = celt_sqrt(i);
|
||||
ratio = val/sqrt(i);
|
||||
if (fabs(ratio - 1) > .0005 && fabs(val-sqrt(i)) > 2)
|
||||
{
|
||||
fprintf (stderr, "sqrt failed: sqrt(%d)="WORD" (ratio = %f)\n", i, val, ratio);
|
||||
ret = 1;
|
||||
}
|
||||
i+= i>>10;
|
||||
}
|
||||
}
|
||||
|
||||
void testbitexactcos(void)
|
||||
{
|
||||
int i;
|
||||
opus_int32 min_d,max_d,last,chk;
|
||||
chk=max_d=0;
|
||||
last=min_d=32767;
|
||||
for(i=64;i<=16320;i++)
|
||||
{
|
||||
opus_int32 d;
|
||||
opus_int32 q=bitexact_cos(i);
|
||||
chk ^= q*i;
|
||||
d = last - q;
|
||||
if (d>max_d)max_d=d;
|
||||
if (d<min_d)min_d=d;
|
||||
last = q;
|
||||
}
|
||||
if ((chk!=89408644)||(max_d!=5)||(min_d!=0)||(bitexact_cos(64)!=32767)||
|
||||
(bitexact_cos(16320)!=200)||(bitexact_cos(8192)!=23171))
|
||||
{
|
||||
fprintf (stderr, "bitexact_cos failed\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void testbitexactlog2tan(void)
|
||||
{
|
||||
int i,fail;
|
||||
opus_int32 min_d,max_d,last,chk;
|
||||
fail=chk=max_d=0;
|
||||
last=min_d=15059;
|
||||
for(i=64;i<8193;i++)
|
||||
{
|
||||
opus_int32 d;
|
||||
opus_int32 mid=bitexact_cos(i);
|
||||
opus_int32 side=bitexact_cos(16384-i);
|
||||
opus_int32 q=bitexact_log2tan(mid,side);
|
||||
chk ^= q*i;
|
||||
d = last - q;
|
||||
if (q!=-1*bitexact_log2tan(side,mid))
|
||||
fail = 1;
|
||||
if (d>max_d)max_d=d;
|
||||
if (d<min_d)min_d=d;
|
||||
last = q;
|
||||
}
|
||||
if ((chk!=15821257)||(max_d!=61)||(min_d!=-2)||fail||
|
||||
(bitexact_log2tan(32767,200)!=15059)||(bitexact_log2tan(30274,12540)!=2611)||
|
||||
(bitexact_log2tan(23171,23171)!=0))
|
||||
{
|
||||
fprintf (stderr, "bitexact_log2tan failed\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef FIXED_POINT
|
||||
void testlog2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=0.001;x<1677700.0;x+=(x/8.0))
|
||||
{
|
||||
float error = fabs((1.442695040888963387*log(x))-celt_log2(x));
|
||||
if (error>0.0009)
|
||||
{
|
||||
fprintf (stderr, "celt_log2 failed: fabs((1.442695040888963387*log(x))-celt_log2(x))>0.001 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=-11.0;x<24.0;x+=0.0007)
|
||||
{
|
||||
float error = fabs(x-(1.442695040888963387*log(celt_exp2(x))));
|
||||
if (error>0.0002)
|
||||
{
|
||||
fprintf (stderr, "celt_exp2 failed: fabs(x-(1.442695040888963387*log(celt_exp2(x))))>0.0005 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2log2(void)
|
||||
{
|
||||
float x;
|
||||
for (x=-11.0;x<24.0;x+=0.0007)
|
||||
{
|
||||
float error = fabs(x-(celt_log2(celt_exp2(x))));
|
||||
if (error>0.001)
|
||||
{
|
||||
fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_log2(celt_exp2(x))))>0.001 (x = %f, error = %f)\n", x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void testlog2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=8;x<1073741824;x+=(x>>3))
|
||||
{
|
||||
float error = fabs((1.442695040888963387*log(x/16384.0))-celt_log2(x)/1024.0);
|
||||
if (error>0.003)
|
||||
{
|
||||
fprintf (stderr, "celt_log2 failed: x = %ld, error = %f\n", (long)x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2(void)
|
||||
{
|
||||
opus_val16 x;
|
||||
for (x=-32768;x<15360;x++)
|
||||
{
|
||||
float error1 = fabs(x/1024.0-(1.442695040888963387*log(celt_exp2(x)/65536.0)));
|
||||
float error2 = fabs(exp(0.6931471805599453094*x/1024.0)-celt_exp2(x)/65536.0);
|
||||
if (error1>0.0002&&error2>0.00004)
|
||||
{
|
||||
fprintf (stderr, "celt_exp2 failed: x = "WORD", error1 = %f, error2 = %f\n", x,error1,error2);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testexp2log2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=8;x<65536;x+=(x>>3))
|
||||
{
|
||||
float error = fabs(x-0.25*celt_exp2(celt_log2(x)))/16384;
|
||||
if (error>0.004)
|
||||
{
|
||||
fprintf (stderr, "celt_log2/celt_exp2 failed: fabs(x-(celt_exp2(celt_log2(x))))>0.001 (x = %ld, error = %f)\n", (long)x,error);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testilog2(void)
|
||||
{
|
||||
opus_val32 x;
|
||||
for (x=1;x<=268435455;x+=127)
|
||||
{
|
||||
opus_val32 lg;
|
||||
opus_val32 y;
|
||||
|
||||
lg = celt_ilog2(x);
|
||||
if (lg<0 || lg>=31)
|
||||
{
|
||||
printf("celt_ilog2 failed: 0<=celt_ilog2(x)<31 (x = %d, celt_ilog2(x) = %d)\n",x,lg);
|
||||
ret = 1;
|
||||
}
|
||||
y = 1<<lg;
|
||||
|
||||
if (x<y || (x>>1)>=y)
|
||||
{
|
||||
printf("celt_ilog2 failed: 2**celt_ilog2(x)<=x<2**(celt_ilog2(x)+1) (x = %d, 2**celt_ilog2(x) = %d)\n",x,y);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
testbitexactcos();
|
||||
testbitexactlog2tan();
|
||||
testdiv();
|
||||
testsqrt();
|
||||
testlog2();
|
||||
testexp2();
|
||||
testexp2log2();
|
||||
#ifdef FIXED_POINT
|
||||
testilog2();
|
||||
#endif
|
||||
return ret;
|
||||
}
|
|
@ -1,230 +0,0 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#define SKIP_CONFIG_H
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define CELT_C
|
||||
#include "mdct.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
#include "kiss_fft.c"
|
||||
#include "mdct.c"
|
||||
#include "mathops.c"
|
||||
#include "entcode.c"
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# include "x86/x86cpu.c"
|
||||
#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/armcpu.c"
|
||||
# include "pitch.c"
|
||||
# include "celt_lpc.c"
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/celt_neon_intr.c"
|
||||
# if defined(HAVE_ARM_NE10)
|
||||
# include "arm/celt_ne10_fft.c"
|
||||
# include "arm/celt_ne10_mdct.c"
|
||||
# endif
|
||||
# endif
|
||||
# include "arm/arm_celt_map.c"
|
||||
#endif
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.141592653
|
||||
#endif
|
||||
|
||||
int ret = 0;
|
||||
void check(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0;
|
||||
double snr;
|
||||
for (bin=0;bin<nfft/2;++bin) {
|
||||
double ansr = 0;
|
||||
double difr;
|
||||
|
||||
for (k=0;k<nfft;++k) {
|
||||
double phase = 2*M_PI*(k+.5+.25*nfft)*(bin+.5)/nfft;
|
||||
double re = cos(phase);
|
||||
|
||||
re /= nfft/4;
|
||||
|
||||
ansr += in[k] * re;
|
||||
}
|
||||
/*printf ("%f %f\n", ansr, out[bin]);*/
|
||||
difr = ansr - out[bin];
|
||||
errpow += difr*difr;
|
||||
sigpow += ansr*ansr;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f **\n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
void check_inv(kiss_fft_scalar * in,kiss_fft_scalar * out,int nfft,int isinverse)
|
||||
{
|
||||
int bin,k;
|
||||
double errpow=0,sigpow=0;
|
||||
double snr;
|
||||
for (bin=0;bin<nfft;++bin) {
|
||||
double ansr = 0;
|
||||
double difr;
|
||||
|
||||
for (k=0;k<nfft/2;++k) {
|
||||
double phase = 2*M_PI*(bin+.5+.25*nfft)*(k+.5)/nfft;
|
||||
double re = cos(phase);
|
||||
|
||||
/*re *= 2;*/
|
||||
|
||||
ansr += in[k] * re;
|
||||
}
|
||||
/*printf ("%f %f\n", ansr, out[bin]);*/
|
||||
difr = ansr - out[bin];
|
||||
errpow += difr*difr;
|
||||
sigpow += ansr*ansr;
|
||||
}
|
||||
snr = 10*log10(sigpow/errpow);
|
||||
printf("nfft=%d inverse=%d,snr = %f\n",nfft,isinverse,snr );
|
||||
if (snr<60) {
|
||||
printf( "** poor snr: %f **\n", snr);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test1d(int nfft,int isinverse,int arch)
|
||||
{
|
||||
mdct_lookup cfg;
|
||||
size_t buflen = sizeof(kiss_fft_scalar)*nfft;
|
||||
|
||||
kiss_fft_scalar * in = (kiss_fft_scalar*)malloc(buflen);
|
||||
kiss_fft_scalar * in_copy = (kiss_fft_scalar*)malloc(buflen);
|
||||
kiss_fft_scalar * out= (kiss_fft_scalar*)malloc(buflen);
|
||||
opus_val16 * window= (opus_val16*)malloc(sizeof(opus_val16)*nfft/2);
|
||||
int k;
|
||||
|
||||
clt_mdct_init(&cfg, nfft, 0, arch);
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] = (rand() % 32768) - 16384;
|
||||
}
|
||||
|
||||
for (k=0;k<nfft/2;++k) {
|
||||
window[k] = Q15ONE;
|
||||
}
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] *= 32768;
|
||||
}
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k) {
|
||||
in[k] /= nfft;
|
||||
}
|
||||
}
|
||||
|
||||
for (k=0;k<nfft;++k)
|
||||
in_copy[k] = in[k];
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", in[k].r, in[k].i);printf("\n");*/
|
||||
|
||||
if (isinverse)
|
||||
{
|
||||
for (k=0;k<nfft;++k)
|
||||
out[k] = 0;
|
||||
clt_mdct_backward(&cfg,in,out, window, nfft/2, 0, 1, arch);
|
||||
/* apply TDAC because clt_mdct_backward() no longer does that */
|
||||
for (k=0;k<nfft/4;++k)
|
||||
out[nfft-k-1] = out[nfft/2+k];
|
||||
check_inv(in,out,nfft,isinverse);
|
||||
} else {
|
||||
clt_mdct_forward(&cfg,in,out,window, nfft/2, 0, 1, arch);
|
||||
check(in_copy,out,nfft,isinverse);
|
||||
}
|
||||
/*for (k=0;k<nfft;++k) printf("%d %d ", out[k].r, out[k].i);printf("\n");*/
|
||||
|
||||
|
||||
free(in);
|
||||
free(in_copy);
|
||||
free(out);
|
||||
free(window);
|
||||
clt_mdct_clear(&cfg, arch);
|
||||
}
|
||||
|
||||
int main(int argc,char ** argv)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
int arch = opus_select_arch();
|
||||
|
||||
if (argc>1) {
|
||||
int k;
|
||||
for (k=1;k<argc;++k) {
|
||||
test1d(atoi(argv[k]),0,arch);
|
||||
test1d(atoi(argv[k]),1,arch);
|
||||
}
|
||||
}else{
|
||||
test1d(32,0,arch);
|
||||
test1d(32,1,arch);
|
||||
test1d(256,0,arch);
|
||||
test1d(256,1,arch);
|
||||
test1d(512,0,arch);
|
||||
test1d(512,1,arch);
|
||||
test1d(1024,0,arch);
|
||||
test1d(1024,1,arch);
|
||||
test1d(2048,0,arch);
|
||||
test1d(2048,1,arch);
|
||||
#ifndef RADIX_TWO_ONLY
|
||||
test1d(36,0,arch);
|
||||
test1d(36,1,arch);
|
||||
test1d(40,0,arch);
|
||||
test1d(40,1,arch);
|
||||
test1d(60,0,arch);
|
||||
test1d(60,1,arch);
|
||||
test1d(120,0,arch);
|
||||
test1d(120,1,arch);
|
||||
test1d(240,0,arch);
|
||||
test1d(240,1,arch);
|
||||
test1d(480,0,arch);
|
||||
test1d(480,1,arch);
|
||||
test1d(960,0,arch);
|
||||
test1d(960,1,arch);
|
||||
test1d(1920,0,arch);
|
||||
test1d(1920,1,arch);
|
||||
#endif
|
||||
}
|
||||
return ret;
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifndef CUSTOM_MODES
|
||||
#define CUSTOM_MODES
|
||||
#endif
|
||||
|
||||
#define CELT_C
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "vq.c"
|
||||
#include "cwrs.c"
|
||||
#include "entcode.c"
|
||||
#include "entenc.c"
|
||||
#include "entdec.c"
|
||||
#include "mathops.c"
|
||||
#include "bands.h"
|
||||
#include "pitch.c"
|
||||
#include "celt_lpc.c"
|
||||
#include "celt.c"
|
||||
#include <math.h>
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE) || defined(OPUS_X86_MAY_HAVE_SSE2) || defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE)
|
||||
# include "x86/pitch_sse.c"
|
||||
# endif
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE2)
|
||||
# include "x86/pitch_sse2.c"
|
||||
# endif
|
||||
# if defined(OPUS_X86_MAY_HAVE_SSE4_1)
|
||||
# include "x86/pitch_sse4_1.c"
|
||||
# include "x86/celt_lpc_sse.c"
|
||||
# endif
|
||||
# include "x86/x86_celt_map.c"
|
||||
#elif defined(OPUS_ARM_ASM) || defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/armcpu.c"
|
||||
# if defined(OPUS_ARM_MAY_HAVE_NEON_INTR)
|
||||
# include "arm/celt_neon_intr.c"
|
||||
# if defined(HAVE_ARM_NE10)
|
||||
# include "kiss_fft.c"
|
||||
# include "mdct.c"
|
||||
# include "arm/celt_ne10_fft.c"
|
||||
# include "arm/celt_ne10_mdct.c"
|
||||
# endif
|
||||
# endif
|
||||
# include "arm/arm_celt_map.c"
|
||||
#endif
|
||||
|
||||
#define MAX_SIZE 100
|
||||
|
||||
int ret=0;
|
||||
void test_rotation(int N, int K)
|
||||
{
|
||||
int i;
|
||||
double err = 0, ener = 0, snr, snr0;
|
||||
opus_val16 x0[MAX_SIZE];
|
||||
opus_val16 x1[MAX_SIZE];
|
||||
for (i=0;i<N;i++)
|
||||
x1[i] = x0[i] = rand()%32767-16384;
|
||||
exp_rotation(x1, N, 1, 1, K, SPREAD_NORMAL);
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
|
||||
ener += x0[i]*(double)x0[i];
|
||||
}
|
||||
snr0 = 20*log10(ener/err);
|
||||
err = ener = 0;
|
||||
exp_rotation(x1, N, -1, 1, K, SPREAD_NORMAL);
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
err += (x0[i]-(double)x1[i])*(x0[i]-(double)x1[i]);
|
||||
ener += x0[i]*(double)x0[i];
|
||||
}
|
||||
snr = 20*log10(ener/err);
|
||||
printf ("SNR for size %d (%d pulses) is %f (was %f without inverse)\n", N, K, snr, snr0);
|
||||
if (snr < 60 || snr0 > 20)
|
||||
{
|
||||
fprintf(stderr, "FAIL!\n");
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
ALLOC_STACK;
|
||||
test_rotation(15, 3);
|
||||
test_rotation(23, 5);
|
||||
test_rotation(50, 3);
|
||||
test_rotation(80, 1);
|
||||
return ret;
|
||||
}
|
|
@ -39,6 +39,10 @@
|
|||
#include "rate.h"
|
||||
#include "pitch.h"
|
||||
|
||||
#if defined(MIPSr1_ASM)
|
||||
#include "mips/vq_mipsr1.h"
|
||||
#endif
|
||||
|
||||
#ifndef OVERRIDE_vq_exp_rotation1
|
||||
static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_val16 s)
|
||||
{
|
||||
|
@ -67,7 +71,7 @@ static void exp_rotation1(celt_norm *X, int len, int stride, opus_val16 c, opus_
|
|||
}
|
||||
#endif /* OVERRIDE_vq_exp_rotation1 */
|
||||
|
||||
static void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
|
||||
void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread)
|
||||
{
|
||||
static const int SPREAD_FACTOR[3]={15,10,5};
|
||||
int i;
|
||||
|
@ -158,42 +162,27 @@ static unsigned extract_collapse_mask(int *iy, int N, int B)
|
|||
return collapse_mask;
|
||||
}
|
||||
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
||||
#ifdef RESYNTH
|
||||
, opus_val16 gain
|
||||
#endif
|
||||
)
|
||||
opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch)
|
||||
{
|
||||
VARDECL(celt_norm, y);
|
||||
VARDECL(int, iy);
|
||||
VARDECL(opus_val16, signx);
|
||||
VARDECL(int, signx);
|
||||
int i, j;
|
||||
opus_val16 s;
|
||||
int pulsesLeft;
|
||||
opus_val32 sum;
|
||||
opus_val32 xy;
|
||||
opus_val16 yy;
|
||||
unsigned collapse_mask;
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert2(K>0, "alg_quant() needs at least one pulse");
|
||||
celt_assert2(N>1, "alg_quant() needs at least two dimensions");
|
||||
|
||||
(void)arch;
|
||||
ALLOC(y, N, celt_norm);
|
||||
ALLOC(iy, N, int);
|
||||
ALLOC(signx, N, opus_val16);
|
||||
|
||||
exp_rotation(X, N, 1, B, K, spread);
|
||||
ALLOC(signx, N, int);
|
||||
|
||||
/* Get rid of the sign */
|
||||
sum = 0;
|
||||
j=0; do {
|
||||
if (X[j]>0)
|
||||
signx[j]=1;
|
||||
else {
|
||||
signx[j]=-1;
|
||||
X[j]=-X[j];
|
||||
}
|
||||
signx[j] = X[j]<0;
|
||||
/* OPT: Make sure the compiler doesn't use a branch on ABS16(). */
|
||||
X[j] = ABS16(X[j]);
|
||||
iy[j] = 0;
|
||||
y[j] = 0;
|
||||
} while (++j<N);
|
||||
|
@ -225,7 +214,12 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
while (++j<N);
|
||||
sum = QCONST16(1.f,14);
|
||||
}
|
||||
rcp = EXTRACT16(MULT16_32_Q16(K-1, celt_rcp(sum)));
|
||||
#ifdef FIXED_POINT
|
||||
rcp = EXTRACT16(MULT16_32_Q16(K, celt_rcp(sum)));
|
||||
#else
|
||||
/* Using K+e with e < 1 guarantees we cannot get more than K pulses. */
|
||||
rcp = EXTRACT16(MULT16_32_Q16(K+0.8f, celt_rcp(sum)));
|
||||
#endif
|
||||
j=0; do {
|
||||
#ifdef FIXED_POINT
|
||||
/* It's really important to round *towards zero* here */
|
||||
|
@ -240,12 +234,12 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
pulsesLeft -= iy[j];
|
||||
} while (++j<N);
|
||||
}
|
||||
celt_assert2(pulsesLeft>=1, "Allocated too many pulses in the quick pass");
|
||||
celt_sig_assert(pulsesLeft>=0);
|
||||
|
||||
/* This should never happen, but just in case it does (e.g. on silence)
|
||||
we fill the first bin with pulses. */
|
||||
#ifdef FIXED_POINT_DEBUG
|
||||
celt_assert2(pulsesLeft<=N+3, "Not enough pulses in the quick pass");
|
||||
celt_sig_assert(pulsesLeft<=N+3);
|
||||
#endif
|
||||
if (pulsesLeft > N+3)
|
||||
{
|
||||
|
@ -256,12 +250,12 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
pulsesLeft=0;
|
||||
}
|
||||
|
||||
s = 1;
|
||||
for (i=0;i<pulsesLeft;i++)
|
||||
{
|
||||
opus_val16 Rxy, Ryy;
|
||||
int best_id;
|
||||
opus_val32 best_num = -VERY_LARGE16;
|
||||
opus_val16 best_den = 0;
|
||||
opus_val32 best_num;
|
||||
opus_val16 best_den;
|
||||
#ifdef FIXED_POINT
|
||||
int rshift;
|
||||
#endif
|
||||
|
@ -272,9 +266,22 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
/* The squared magnitude term gets added anyway, so we might as well
|
||||
add it outside the loop */
|
||||
yy = ADD16(yy, 1);
|
||||
j=0;
|
||||
|
||||
/* Calculations for position 0 are out of the loop, in part to reduce
|
||||
mispredicted branches (since the if condition is usually false)
|
||||
in the loop. */
|
||||
/* Temporary sums of the new pulse(s) */
|
||||
Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[0])),rshift));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
Ryy = ADD16(yy, y[0]);
|
||||
|
||||
/* Approximate score: we maximise Rxy/sqrt(Ryy) (we're guaranteed that
|
||||
Rxy is positive because the sign is pre-computed) */
|
||||
Rxy = MULT16_16_Q15(Rxy,Rxy);
|
||||
best_den = Ryy;
|
||||
best_num = Rxy;
|
||||
j=1;
|
||||
do {
|
||||
opus_val16 Rxy, Ryy;
|
||||
/* Temporary sums of the new pulse(s) */
|
||||
Rxy = EXTRACT16(SHR32(ADD32(xy, EXTEND32(X[j])),rshift));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
|
@ -285,8 +292,11 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
Rxy = MULT16_16_Q15(Rxy,Rxy);
|
||||
/* The idea is to check for num/den >= best_num/best_den, but that way
|
||||
we can do it without any division */
|
||||
/* OPT: Make sure to use conditional moves here */
|
||||
if (MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num))
|
||||
/* OPT: It's not clear whether a cmov is faster than a branch here
|
||||
since the condition is more often false than true and using
|
||||
a cmov introduces data dependencies across iterations. The optimal
|
||||
choice may be architecture-dependent. */
|
||||
if (opus_unlikely(MULT16_16(best_den, Rxy) > MULT16_16(Ryy, best_num)))
|
||||
{
|
||||
best_den = Ryy;
|
||||
best_num = Rxy;
|
||||
|
@ -301,23 +311,47 @@ unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc
|
|||
|
||||
/* Only now that we've made the final choice, update y/iy */
|
||||
/* Multiplying y[j] by 2 so we don't have to do it everywhere else */
|
||||
y[best_id] += 2*s;
|
||||
y[best_id] += 2;
|
||||
iy[best_id]++;
|
||||
}
|
||||
|
||||
/* Put the original sign back */
|
||||
j=0;
|
||||
do {
|
||||
X[j] = MULT16_16(signx[j],X[j]);
|
||||
if (signx[j] < 0)
|
||||
iy[j] = -iy[j];
|
||||
/*iy[j] = signx[j] ? -iy[j] : iy[j];*/
|
||||
/* OPT: The is more likely to be compiled without a branch than the code above
|
||||
but has the same performance otherwise. */
|
||||
iy[j] = (iy[j]^-signx[j]) + signx[j];
|
||||
} while (++j<N);
|
||||
RESTORE_STACK;
|
||||
return yy;
|
||||
}
|
||||
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc,
|
||||
opus_val16 gain, int resynth, int arch)
|
||||
{
|
||||
VARDECL(int, iy);
|
||||
opus_val16 yy;
|
||||
unsigned collapse_mask;
|
||||
SAVE_STACK;
|
||||
|
||||
celt_assert2(K>0, "alg_quant() needs at least one pulse");
|
||||
celt_assert2(N>1, "alg_quant() needs at least two dimensions");
|
||||
|
||||
/* Covers vectorization by up to 4. */
|
||||
ALLOC(iy, N+3, int);
|
||||
|
||||
exp_rotation(X, N, 1, B, K, spread);
|
||||
|
||||
yy = op_pvq_search(X, iy, K, N, arch);
|
||||
|
||||
encode_pulses(iy, N, K, enc);
|
||||
|
||||
#ifdef RESYNTH
|
||||
normalise_residual(iy, X, N, yy, gain);
|
||||
exp_rotation(X, N, -1, B, K, spread);
|
||||
#endif
|
||||
if (resynth)
|
||||
{
|
||||
normalise_residual(iy, X, N, yy, gain);
|
||||
exp_rotation(X, N, -1, B, K, spread);
|
||||
}
|
||||
|
||||
collapse_mask = extract_collapse_mask(iy, N, B);
|
||||
RESTORE_STACK;
|
||||
|
@ -401,7 +435,7 @@ int stereo_itheta(const celt_norm *X, const celt_norm *Y, int stereo, int N, int
|
|||
/* 0.63662 = 2/pi */
|
||||
itheta = MULT16_16_Q15(QCONST16(0.63662f,15),celt_atan2p(side, mid));
|
||||
#else
|
||||
itheta = (int)floor(.5f+16384*0.63662f*atan2(side,mid));
|
||||
itheta = (int)floor(.5f+16384*0.63662f*fast_atan2f(side,mid));
|
||||
#endif
|
||||
|
||||
return itheta;
|
||||
|
|
|
@ -37,10 +37,18 @@
|
|||
#include "entdec.h"
|
||||
#include "modes.h"
|
||||
|
||||
#if defined(MIPSr1_ASM)
|
||||
#include "mips/vq_mipsr1.h"
|
||||
#if (defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT))
|
||||
#include "x86/vq_sse.h"
|
||||
#endif
|
||||
|
||||
void exp_rotation(celt_norm *X, int len, int dir, int stride, int K, int spread);
|
||||
|
||||
opus_val16 op_pvq_search_c(celt_norm *X, int *iy, int K, int N, int arch);
|
||||
|
||||
#if !defined(OVERRIDE_OP_PVQ_SEARCH)
|
||||
#define op_pvq_search(x, iy, K, N, arch) \
|
||||
(op_pvq_search_c(x, iy, K, N, arch))
|
||||
#endif
|
||||
|
||||
/** Algebraic pulse-vector quantiser. The signal x is replaced by the sum of
|
||||
* the pitch and a combination of pulses such that its norm is still equal
|
||||
|
@ -51,12 +59,8 @@
|
|||
* @param enc Entropy encoder state
|
||||
* @ret A mask indicating which blocks in the band received pulses
|
||||
*/
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B,
|
||||
ec_enc *enc
|
||||
#ifdef RESYNTH
|
||||
, opus_val16 gain
|
||||
#endif
|
||||
);
|
||||
unsigned alg_quant(celt_norm *X, int N, int K, int spread, int B, ec_enc *enc,
|
||||
opus_val16 gain, int resynth, int arch);
|
||||
|
||||
/** Algebraic pulse decoder
|
||||
* @param X Decoded normalised spectrum (returned)
|
||||
|
|
|
@ -41,12 +41,11 @@ void celt_fir_sse4_1(
|
|||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch);
|
||||
|
||||
#if defined(OPUS_X86_PRESUME_SSE4_1)
|
||||
#define celt_fir(x, num, y, N, ord, mem, arch) \
|
||||
((void)arch, celt_fir_sse4_1(x, num, y, N, ord, mem, arch))
|
||||
#define celt_fir(x, num, y, N, ord, arch) \
|
||||
((void)arch, celt_fir_sse4_1(x, num, y, N, ord, arch))
|
||||
|
||||
#else
|
||||
|
||||
|
@ -56,11 +55,10 @@ extern void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
|
|||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch);
|
||||
|
||||
# define celt_fir(x, num, y, N, ord, mem, arch) \
|
||||
((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, mem, arch))
|
||||
# define celt_fir(x, num, y, N, ord, arch) \
|
||||
((*CELT_FIR_IMPL[(arch) & OPUS_ARCHMASK])(x, num, y, N, ord, arch))
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -40,65 +40,23 @@
|
|||
|
||||
#if defined(FIXED_POINT)
|
||||
|
||||
void celt_fir_sse4_1(const opus_val16 *_x,
|
||||
void celt_fir_sse4_1(const opus_val16 *x,
|
||||
const opus_val16 *num,
|
||||
opus_val16 *_y,
|
||||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch)
|
||||
{
|
||||
int i,j;
|
||||
VARDECL(opus_val16, rnum);
|
||||
VARDECL(opus_val16, x);
|
||||
|
||||
__m128i vecNoA;
|
||||
opus_int32 noA ;
|
||||
SAVE_STACK;
|
||||
|
||||
ALLOC(rnum, ord, opus_val16);
|
||||
ALLOC(x, N+ord, opus_val16);
|
||||
for(i=0;i<ord;i++)
|
||||
rnum[i] = num[ord-i-1];
|
||||
for(i=0;i<ord;i++)
|
||||
x[i] = mem[ord-i-1];
|
||||
|
||||
for (i=0;i<N-7;i+=8)
|
||||
{
|
||||
x[i+ord ]=_x[i ];
|
||||
x[i+ord+1]=_x[i+1];
|
||||
x[i+ord+2]=_x[i+2];
|
||||
x[i+ord+3]=_x[i+3];
|
||||
x[i+ord+4]=_x[i+4];
|
||||
x[i+ord+5]=_x[i+5];
|
||||
x[i+ord+6]=_x[i+6];
|
||||
x[i+ord+7]=_x[i+7];
|
||||
}
|
||||
|
||||
for (;i<N-3;i+=4)
|
||||
{
|
||||
x[i+ord ]=_x[i ];
|
||||
x[i+ord+1]=_x[i+1];
|
||||
x[i+ord+2]=_x[i+2];
|
||||
x[i+ord+3]=_x[i+3];
|
||||
}
|
||||
|
||||
for (;i<N;i++)
|
||||
x[i+ord]=_x[i];
|
||||
|
||||
for(i=0;i<ord;i++)
|
||||
mem[i] = _x[N-i-1];
|
||||
#ifdef SMALL_FOOTPRINT
|
||||
for (i=0;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = SHL32(EXTEND32(_x[i]), SIG_SHIFT);
|
||||
for (j=0;j<ord;j++)
|
||||
{
|
||||
sum = MAC16_16(sum,rnum[j],x[i+j]);
|
||||
}
|
||||
_y[i] = SATURATE16(PSHR32(sum, SIG_SHIFT));
|
||||
}
|
||||
#else
|
||||
noA = EXTEND32(1) << SIG_SHIFT >> 1;
|
||||
vecNoA = _mm_set_epi32(noA, noA, noA, noA);
|
||||
|
||||
|
@ -107,25 +65,24 @@ void celt_fir_sse4_1(const opus_val16 *_x,
|
|||
opus_val32 sums[4] = {0};
|
||||
__m128i vecSum, vecX;
|
||||
|
||||
xcorr_kernel(rnum, x+i, sums, ord, arch);
|
||||
xcorr_kernel(rnum, x+i-ord, sums, ord, arch);
|
||||
|
||||
vecSum = _mm_loadu_si128((__m128i *)sums);
|
||||
vecSum = _mm_add_epi32(vecSum, vecNoA);
|
||||
vecSum = _mm_srai_epi32(vecSum, SIG_SHIFT);
|
||||
vecX = OP_CVTEPI16_EPI32_M64(_x + i);
|
||||
vecX = OP_CVTEPI16_EPI32_M64(x + i);
|
||||
vecSum = _mm_add_epi32(vecSum, vecX);
|
||||
vecSum = _mm_packs_epi32(vecSum, vecSum);
|
||||
_mm_storel_epi64((__m128i *)(_y + i), vecSum);
|
||||
_mm_storel_epi64((__m128i *)(y + i), vecSum);
|
||||
}
|
||||
for (;i<N;i++)
|
||||
{
|
||||
opus_val32 sum = 0;
|
||||
for (j=0;j<ord;j++)
|
||||
sum = MAC16_16(sum, rnum[j], x[i + j]);
|
||||
_y[i] = SATURATE16(ADD32(EXTEND32(_x[i]), PSHR32(sum, SIG_SHIFT)));
|
||||
sum = MAC16_16(sum, rnum[j], x[i+j-ord]);
|
||||
y[i] = SATURATE16(ADD32(EXTEND32(x[i]), PSHR32(sum, SIG_SHIFT)));
|
||||
}
|
||||
|
||||
#endif
|
||||
RESTORE_STACK;
|
||||
}
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
/* Copyright (c) 2008-2011 Xiph.Org Foundation
|
||||
Written by Jean-Marc Valin */
|
||||
/* Copyright (c) 2016 Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -25,26 +24,27 @@
|
|||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#ifndef VQ_SSE_H
|
||||
#define VQ_SSE_H
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(FIXED_POINT)
|
||||
#define OVERRIDE_OP_PVQ_SEARCH
|
||||
|
||||
opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch);
|
||||
|
||||
#if defined(OPUS_X86_PRESUME_SSE2)
|
||||
#define op_pvq_search(x, iy, K, N, arch) \
|
||||
(op_pvq_search_sse2(x, iy, K, N, arch))
|
||||
|
||||
#else
|
||||
|
||||
extern opus_val16 (*const OP_PVQ_SEARCH_IMPL[OPUS_ARCHMASK + 1])(
|
||||
celt_norm *_X, int *iy, int K, int N, int arch);
|
||||
|
||||
# define op_pvq_search(X, iy, K, N, arch) \
|
||||
((*OP_PVQ_SEARCH_IMPL[(arch) & OPUS_ARCHMASK])(X, iy, K, N, arch))
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "opus_types.h"
|
||||
#include <stdio.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
opus_int16 i = 1;
|
||||
i <<= 14;
|
||||
if (i>>14 != 1)
|
||||
{
|
||||
fprintf(stderr, "opus_int16 isn't 16 bits\n");
|
||||
return 1;
|
||||
}
|
||||
if (sizeof(opus_int16)*2 != sizeof(opus_int32))
|
||||
{
|
||||
fprintf(stderr, "16*2 != 32\n");
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,217 @@
|
|||
/* Copyright (c) 2007-2008 CSIRO
|
||||
Copyright (c) 2007-2009 Xiph.Org Foundation
|
||||
Copyright (c) 2007-2016 Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <xmmintrin.h>
|
||||
#include <emmintrin.h>
|
||||
#include "celt_lpc.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "mathops.h"
|
||||
#include "vq.h"
|
||||
#include "x86cpu.h"
|
||||
|
||||
|
||||
#ifndef FIXED_POINT
|
||||
|
||||
opus_val16 op_pvq_search_sse2(celt_norm *_X, int *iy, int K, int N, int arch)
|
||||
{
|
||||
int i, j;
|
||||
int pulsesLeft;
|
||||
float xy, yy;
|
||||
VARDECL(celt_norm, y);
|
||||
VARDECL(celt_norm, X);
|
||||
VARDECL(float, signy);
|
||||
__m128 signmask;
|
||||
__m128 sums;
|
||||
__m128i fours;
|
||||
SAVE_STACK;
|
||||
|
||||
(void)arch;
|
||||
/* All bits set to zero, except for the sign bit. */
|
||||
signmask = _mm_set_ps1(-0.f);
|
||||
fours = _mm_set_epi32(4, 4, 4, 4);
|
||||
ALLOC(y, N+3, celt_norm);
|
||||
ALLOC(X, N+3, celt_norm);
|
||||
ALLOC(signy, N+3, float);
|
||||
|
||||
OPUS_COPY(X, _X, N);
|
||||
X[N] = X[N+1] = X[N+2] = 0;
|
||||
sums = _mm_setzero_ps();
|
||||
for (j=0;j<N;j+=4)
|
||||
{
|
||||
__m128 x4, s4;
|
||||
x4 = _mm_loadu_ps(&X[j]);
|
||||
s4 = _mm_cmplt_ps(x4, _mm_setzero_ps());
|
||||
/* Get rid of the sign */
|
||||
x4 = _mm_andnot_ps(signmask, x4);
|
||||
sums = _mm_add_ps(sums, x4);
|
||||
/* Clear y and iy in case we don't do the projection. */
|
||||
_mm_storeu_ps(&y[j], _mm_setzero_ps());
|
||||
_mm_storeu_si128((__m128i*)&iy[j], _mm_setzero_si128());
|
||||
_mm_storeu_ps(&X[j], x4);
|
||||
_mm_storeu_ps(&signy[j], s4);
|
||||
}
|
||||
sums = _mm_add_ps(sums, _mm_shuffle_ps(sums, sums, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
sums = _mm_add_ps(sums, _mm_shuffle_ps(sums, sums, _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
|
||||
xy = yy = 0;
|
||||
|
||||
pulsesLeft = K;
|
||||
|
||||
/* Do a pre-search by projecting on the pyramid */
|
||||
if (K > (N>>1))
|
||||
{
|
||||
__m128i pulses_sum;
|
||||
__m128 yy4, xy4;
|
||||
__m128 rcp4;
|
||||
opus_val32 sum = _mm_cvtss_f32(sums);
|
||||
/* If X is too small, just replace it with a pulse at 0 */
|
||||
/* Prevents infinities and NaNs from causing too many pulses
|
||||
to be allocated. 64 is an approximation of infinity here. */
|
||||
if (!(sum > EPSILON && sum < 64))
|
||||
{
|
||||
X[0] = QCONST16(1.f,14);
|
||||
j=1; do
|
||||
X[j]=0;
|
||||
while (++j<N);
|
||||
sums = _mm_set_ps1(1.f);
|
||||
}
|
||||
/* Using K+e with e < 1 guarantees we cannot get more than K pulses. */
|
||||
rcp4 = _mm_mul_ps(_mm_set_ps1((float)(K+.8)), _mm_rcp_ps(sums));
|
||||
xy4 = yy4 = _mm_setzero_ps();
|
||||
pulses_sum = _mm_setzero_si128();
|
||||
for (j=0;j<N;j+=4)
|
||||
{
|
||||
__m128 rx4, x4, y4;
|
||||
__m128i iy4;
|
||||
x4 = _mm_loadu_ps(&X[j]);
|
||||
rx4 = _mm_mul_ps(x4, rcp4);
|
||||
iy4 = _mm_cvttps_epi32(rx4);
|
||||
pulses_sum = _mm_add_epi32(pulses_sum, iy4);
|
||||
_mm_storeu_si128((__m128i*)&iy[j], iy4);
|
||||
y4 = _mm_cvtepi32_ps(iy4);
|
||||
xy4 = _mm_add_ps(xy4, _mm_mul_ps(x4, y4));
|
||||
yy4 = _mm_add_ps(yy4, _mm_mul_ps(y4, y4));
|
||||
/* double the y[] vector so we don't have to do it in the search loop. */
|
||||
_mm_storeu_ps(&y[j], _mm_add_ps(y4, y4));
|
||||
}
|
||||
pulses_sum = _mm_add_epi32(pulses_sum, _mm_shuffle_epi32(pulses_sum, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
pulses_sum = _mm_add_epi32(pulses_sum, _mm_shuffle_epi32(pulses_sum, _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
pulsesLeft -= _mm_cvtsi128_si32(pulses_sum);
|
||||
xy4 = _mm_add_ps(xy4, _mm_shuffle_ps(xy4, xy4, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
xy4 = _mm_add_ps(xy4, _mm_shuffle_ps(xy4, xy4, _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
xy = _mm_cvtss_f32(xy4);
|
||||
yy4 = _mm_add_ps(yy4, _mm_shuffle_ps(yy4, yy4, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
yy4 = _mm_add_ps(yy4, _mm_shuffle_ps(yy4, yy4, _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
yy = _mm_cvtss_f32(yy4);
|
||||
}
|
||||
X[N] = X[N+1] = X[N+2] = -100;
|
||||
y[N] = y[N+1] = y[N+2] = 100;
|
||||
celt_sig_assert(pulsesLeft>=0);
|
||||
|
||||
/* This should never happen, but just in case it does (e.g. on silence)
|
||||
we fill the first bin with pulses. */
|
||||
if (pulsesLeft > N+3)
|
||||
{
|
||||
opus_val16 tmp = (opus_val16)pulsesLeft;
|
||||
yy = MAC16_16(yy, tmp, tmp);
|
||||
yy = MAC16_16(yy, tmp, y[0]);
|
||||
iy[0] += pulsesLeft;
|
||||
pulsesLeft=0;
|
||||
}
|
||||
|
||||
for (i=0;i<pulsesLeft;i++)
|
||||
{
|
||||
int best_id;
|
||||
__m128 xy4, yy4;
|
||||
__m128 max, max2;
|
||||
__m128i count;
|
||||
__m128i pos;
|
||||
/* The squared magnitude term gets added anyway, so we might as well
|
||||
add it outside the loop */
|
||||
yy = ADD16(yy, 1);
|
||||
xy4 = _mm_load1_ps(&xy);
|
||||
yy4 = _mm_load1_ps(&yy);
|
||||
max = _mm_setzero_ps();
|
||||
pos = _mm_setzero_si128();
|
||||
count = _mm_set_epi32(3, 2, 1, 0);
|
||||
for (j=0;j<N;j+=4)
|
||||
{
|
||||
__m128 x4, y4, r4;
|
||||
x4 = _mm_loadu_ps(&X[j]);
|
||||
y4 = _mm_loadu_ps(&y[j]);
|
||||
x4 = _mm_add_ps(x4, xy4);
|
||||
y4 = _mm_add_ps(y4, yy4);
|
||||
y4 = _mm_rsqrt_ps(y4);
|
||||
r4 = _mm_mul_ps(x4, y4);
|
||||
/* Update the index of the max. */
|
||||
pos = _mm_max_epi16(pos, _mm_and_si128(count, _mm_castps_si128(_mm_cmpgt_ps(r4, max))));
|
||||
/* Update the max. */
|
||||
max = _mm_max_ps(max, r4);
|
||||
/* Update the indices (+4) */
|
||||
count = _mm_add_epi32(count, fours);
|
||||
}
|
||||
/* Horizontal max */
|
||||
max2 = _mm_max_ps(max, _mm_shuffle_ps(max, max, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
max2 = _mm_max_ps(max2, _mm_shuffle_ps(max2, max2, _MM_SHUFFLE(2, 3, 0, 1)));
|
||||
/* Now that max2 contains the max at all positions, look at which value(s) of the
|
||||
partial max is equal to the global max. */
|
||||
pos = _mm_and_si128(pos, _mm_castps_si128(_mm_cmpeq_ps(max, max2)));
|
||||
pos = _mm_max_epi16(pos, _mm_unpackhi_epi64(pos, pos));
|
||||
pos = _mm_max_epi16(pos, _mm_shufflelo_epi16(pos, _MM_SHUFFLE(1, 0, 3, 2)));
|
||||
best_id = _mm_cvtsi128_si32(pos);
|
||||
|
||||
/* Updating the sums of the new pulse(s) */
|
||||
xy = ADD32(xy, EXTEND32(X[best_id]));
|
||||
/* We're multiplying y[j] by two so we don't have to do it here */
|
||||
yy = ADD16(yy, y[best_id]);
|
||||
|
||||
/* Only now that we've made the final choice, update y/iy */
|
||||
/* Multiplying y[j] by 2 so we don't have to do it everywhere else */
|
||||
y[best_id] += 2;
|
||||
iy[best_id]++;
|
||||
}
|
||||
|
||||
/* Put the original sign back */
|
||||
for (j=0;j<N;j+=4)
|
||||
{
|
||||
__m128i y4;
|
||||
__m128i s4;
|
||||
y4 = _mm_loadu_si128((__m128i*)&iy[j]);
|
||||
s4 = _mm_castps_si128(_mm_loadu_ps(&signy[j]));
|
||||
y4 = _mm_xor_si128(_mm_add_epi32(y4, s4), s4);
|
||||
_mm_storeu_si128((__m128i*)&iy[j], y4);
|
||||
}
|
||||
RESTORE_STACK;
|
||||
return yy;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -33,6 +33,7 @@
|
|||
#include "celt_lpc.h"
|
||||
#include "pitch.h"
|
||||
#include "pitch_sse.h"
|
||||
#include "vq.h"
|
||||
|
||||
#if defined(OPUS_HAVE_RTCD)
|
||||
|
||||
|
@ -46,7 +47,6 @@ void (*const CELT_FIR_IMPL[OPUS_ARCHMASK + 1])(
|
|||
opus_val16 *y,
|
||||
int N,
|
||||
int ord,
|
||||
opus_val16 *mem,
|
||||
int arch
|
||||
) = {
|
||||
celt_fir_c, /* non-sse */
|
||||
|
@ -151,5 +151,17 @@ void (*const COMB_FILTER_CONST_IMPL[OPUS_ARCHMASK + 1])(
|
|||
|
||||
#endif
|
||||
|
||||
#if defined(OPUS_X86_MAY_HAVE_SSE2) && !defined(OPUS_X86_PRESUME_SSE2)
|
||||
opus_val16 (*const OP_PVQ_SEARCH_IMPL[OPUS_ARCHMASK + 1])(
|
||||
celt_norm *_X, int *iy, int K, int N, int arch
|
||||
) = {
|
||||
op_pvq_search_c, /* non-sse */
|
||||
op_pvq_search_c,
|
||||
MAY_HAVE_SSE2(op_pvq_search),
|
||||
MAY_HAVE_SSE2(op_pvq_search),
|
||||
MAY_HAVE_SSE2(op_pvq_search)
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -82,7 +82,9 @@ int opus_select_arch(void);
|
|||
(_mm_cvtepi8_epi32(*(__m128i *)(x)))
|
||||
#endif
|
||||
|
||||
# if !defined(__OPTIMIZE__)
|
||||
/* similar reasoning about the instruction sequence as in the 32-bit macro above,
|
||||
*/
|
||||
# if defined(__clang__) || !defined(__OPTIMIZE__)
|
||||
# define OP_CVTEPI16_EPI32_M64(x) \
|
||||
(_mm_cvtepi16_epi32(_mm_loadl_epi64((__m128i *)(x))))
|
||||
# else
|
||||
|
|
|
@ -1,5 +1,44 @@
|
|||
/* Opus configuration header */
|
||||
/* Based on the output of libopus configure script */
|
||||
/* config.h. Generated from config.h.in by configure. */
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Get CPU Info by asm method */
|
||||
#define CPU_INFO_BY_ASM 1
|
||||
|
||||
/* Get CPU Info by c method */
|
||||
/* #undef CPU_INFO_BY_C */
|
||||
|
||||
/* Custom modes */
|
||||
/* #undef CUSTOM_MODES */
|
||||
|
||||
/* Do not build the float API */
|
||||
/* #undef DISABLE_FLOAT_API */
|
||||
|
||||
/* Disable bitstream fixes from RFC 8251 */
|
||||
/* #undef DISABLE_UPDATE_DRAFT */
|
||||
|
||||
/* Assertions */
|
||||
/* #undef ENABLE_ASSERTIONS */
|
||||
|
||||
/* Hardening */
|
||||
#define ENABLE_HARDENING 1
|
||||
|
||||
/* Debug fixed-point implementation */
|
||||
/* #undef FIXED_DEBUG */
|
||||
|
||||
/* Compile as fixed-point (for machines without a fast enough FPU) */
|
||||
/* #undef FIXED_POINT */
|
||||
|
||||
/* Float approximations */
|
||||
/* #undef FLOAT_APPROX */
|
||||
|
||||
/* Fuzzing */
|
||||
/* #undef FUZZING */
|
||||
|
||||
/* Define to 1 if you have the <alloca.h> header file. */
|
||||
/* #undef HAVE_ALLOCA_H */
|
||||
|
||||
/* NE10 library is installed on host. Make sure it is on target! */
|
||||
/* #undef HAVE_ARM_NE10 */
|
||||
|
||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||
#define HAVE_DLFCN_H 1
|
||||
|
@ -41,6 +80,9 @@
|
|||
/* Define to 1 if you have the <unistd.h> header file. */
|
||||
#define HAVE_UNISTD_H 1
|
||||
|
||||
/* Define to 1 if you have the `__malloc_hook' function. */
|
||||
#define HAVE___MALLOC_HOOK 1
|
||||
|
||||
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||
*/
|
||||
#define LT_OBJDIR ".libs/"
|
||||
|
@ -92,9 +134,80 @@
|
|||
|
||||
#endif // OPUS_ARM64_OPT
|
||||
|
||||
/* Define if binary requires Aarch64 Neon Intrinsics */
|
||||
/* #undef OPUS_ARM_PRESUME_AARCH64_NEON_INTR */
|
||||
|
||||
/* Define if binary requires EDSP instruction support */
|
||||
/* #undef OPUS_ARM_PRESUME_EDSP */
|
||||
|
||||
/* Define if binary requires ARMv6 media instruction support */
|
||||
/* #undef OPUS_ARM_PRESUME_MEDIA */
|
||||
|
||||
/* Define if binary requires NEON instruction support */
|
||||
/* #undef OPUS_ARM_PRESUME_NEON */
|
||||
|
||||
/* Define if binary requires NEON intrinsics support */
|
||||
/* #undef OPUS_ARM_PRESUME_NEON_INTR */
|
||||
|
||||
/* This is a build of OPUS */
|
||||
#define OPUS_BUILD /**/
|
||||
|
||||
/* Run bit-exactness checks between optimized and c implementations */
|
||||
/* #undef OPUS_CHECK_ASM */
|
||||
|
||||
#ifndef OPUS_ARM_OPT
|
||||
/* Use run-time CPU capabilities detection */
|
||||
#define OPUS_HAVE_RTCD 1
|
||||
#endif
|
||||
|
||||
/* Compiler supports X86 AVX Intrinsics */
|
||||
/* #define OPUS_X86_MAY_HAVE_AVX */
|
||||
|
||||
/* Compiler supports X86 SSE Intrinsics */
|
||||
/* #define OPUS_X86_MAY_HAVE_SSE */
|
||||
|
||||
/* Compiler supports X86 SSE2 Intrinsics */
|
||||
/* #define OPUS_X86_MAY_HAVE_SSE2 */
|
||||
|
||||
/* Compiler supports X86 SSE4.1 Intrinsics */
|
||||
/* #define OPUS_X86_MAY_HAVE_SSE4_1 */
|
||||
|
||||
/* Define if binary requires AVX intrinsics support */
|
||||
/* #undef OPUS_X86_PRESUME_AVX */
|
||||
|
||||
/* Define if binary requires SSE intrinsics support */
|
||||
#define OPUS_X86_PRESUME_SSE 1
|
||||
|
||||
/* Define if binary requires SSE2 intrinsics support */
|
||||
#define OPUS_X86_PRESUME_SSE2 1
|
||||
|
||||
/* Define if binary requires SSE4.1 intrinsics support */
|
||||
#define OPUS_X86_PRESUME_SSE4_1 1
|
||||
|
||||
/* Define to the address where bug reports for this package should be sent. */
|
||||
#define PACKAGE_BUGREPORT "opus@xiph.org"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "opus"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "opus unknown"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "opus"
|
||||
|
||||
/* Define to the home page for this package. */
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "unknown"
|
||||
|
||||
/* Define to 1 if you have the ANSI C header files. */
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
/* Make use of alloca */
|
||||
/* #undef USE_ALLOCA */
|
||||
|
||||
#ifndef WIN32
|
||||
/* Use C99 variable-size arrays */
|
||||
#define VAR_ARRAYS 1
|
||||
|
@ -103,11 +216,13 @@
|
|||
#define USE_ALLOCA 1
|
||||
#endif
|
||||
|
||||
/* Define to empty if `const' does not conform to ANSI C. */
|
||||
/* #undef const */
|
||||
|
||||
#ifndef OPUS_FIXED_POINT
|
||||
#define FLOAT_APPROX 1
|
||||
#endif
|
||||
|
||||
|
||||
/* Define to `__inline__' or `__inline' if that's what the C compiler
|
||||
calls it, or to nothing if 'inline' is not supported under any name. */
|
||||
#ifndef __cplusplus
|
||||
|
|
|
@ -107,26 +107,32 @@ static int op_tags_ensure_capacity(OpusTags *_tags,size_t _ncomments){
|
|||
char **user_comments;
|
||||
int *comment_lengths;
|
||||
int cur_ncomments;
|
||||
char *binary_suffix_data;
|
||||
int binary_suffix_len;
|
||||
size_t size;
|
||||
if(OP_UNLIKELY(_ncomments>=(size_t)INT_MAX))return OP_EFAULT;
|
||||
size=sizeof(*_tags->comment_lengths)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->comment_lengths)!=_ncomments+1)return OP_EFAULT;
|
||||
cur_ncomments=_tags->comments;
|
||||
comment_lengths=_tags->comment_lengths;
|
||||
binary_suffix_len=comment_lengths==NULL?0:comment_lengths[cur_ncomments];
|
||||
/*We only support growing.
|
||||
Trimming requires cleaning up the allocated strings in the old space, and
|
||||
is best handled separately if it's ever needed.*/
|
||||
OP_ASSERT(_ncomments>=(size_t)cur_ncomments);
|
||||
comment_lengths=(int *)_ogg_realloc(_tags->comment_lengths,size);
|
||||
if(OP_UNLIKELY(comment_lengths==NULL))return OP_EFAULT;
|
||||
comment_lengths[_ncomments]=binary_suffix_len;
|
||||
if(_tags->comment_lengths==NULL){
|
||||
OP_ASSERT(cur_ncomments==0);
|
||||
comment_lengths[cur_ncomments]=0;
|
||||
}
|
||||
comment_lengths[_ncomments]=comment_lengths[cur_ncomments];
|
||||
_tags->comment_lengths=comment_lengths;
|
||||
size=sizeof(*_tags->user_comments)*(_ncomments+1);
|
||||
if(size/sizeof(*_tags->user_comments)!=_ncomments+1)return OP_EFAULT;
|
||||
user_comments=_tags->user_comments;
|
||||
binary_suffix_data=user_comments==NULL?NULL:user_comments[cur_ncomments];
|
||||
user_comments=(char **)_ogg_realloc(_tags->user_comments,size);
|
||||
if(OP_UNLIKELY(user_comments==NULL))return OP_EFAULT;
|
||||
user_comments[_ncomments]=binary_suffix_data;
|
||||
if(_tags->user_comments==NULL){
|
||||
OP_ASSERT(cur_ncomments==0);
|
||||
user_comments[cur_ncomments]=NULL;
|
||||
}
|
||||
user_comments[_ncomments]=user_comments[cur_ncomments];
|
||||
_tags->user_comments=user_comments;
|
||||
return 0;
|
||||
}
|
||||
|
@ -275,28 +281,30 @@ int opus_tags_copy(OpusTags *_dst,const OpusTags *_src){
|
|||
ret=opus_tags_copy_impl(&dst,_src);
|
||||
if(OP_UNLIKELY(ret<0))opus_tags_clear(&dst);
|
||||
else *_dst=*&dst;
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int opus_tags_add(OpusTags *_tags,const char *_tag,const char *_value){
|
||||
char *comment;
|
||||
int tag_len;
|
||||
int value_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
char *comment;
|
||||
size_t tag_len;
|
||||
size_t value_len;
|
||||
int ncomments;
|
||||
int ret;
|
||||
ncomments=_tags->comments;
|
||||
ret=op_tags_ensure_capacity(_tags,ncomments+1);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
tag_len=strlen(_tag);
|
||||
value_len=strlen(_value);
|
||||
/*+2 for '=' and '\0'.*/
|
||||
if(tag_len+value_len<tag_len)return OP_EFAULT;
|
||||
if(tag_len+value_len>(size_t)INT_MAX-2)return OP_EFAULT;
|
||||
comment=(char *)_ogg_malloc(sizeof(*comment)*(tag_len+value_len+2));
|
||||
if(OP_UNLIKELY(comment==NULL))return OP_EFAULT;
|
||||
memcpy(comment,_tag,sizeof(*comment)*tag_len);
|
||||
comment[tag_len]='=';
|
||||
memcpy(comment+tag_len+1,_value,sizeof(*comment)*(value_len+1));
|
||||
_tags->user_comments[ncomments]=comment;
|
||||
_tags->comment_lengths[ncomments]=tag_len+value_len+1;
|
||||
_tags->comment_lengths[ncomments]=(int)(tag_len+value_len+1);
|
||||
_tags->comments=ncomments+1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -337,7 +345,10 @@ int opus_tags_set_binary_suffix(OpusTags *_tags,
|
|||
}
|
||||
|
||||
int opus_tagcompare(const char *_tag_name,const char *_comment){
|
||||
return opus_tagncompare(_tag_name,strlen(_tag_name),_comment);
|
||||
size_t tag_len;
|
||||
tag_len=strlen(_tag_name);
|
||||
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return -1;
|
||||
return opus_tagncompare(_tag_name,(int)tag_len,_comment);
|
||||
}
|
||||
|
||||
int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
|
||||
|
@ -348,17 +359,18 @@ int opus_tagncompare(const char *_tag_name,int _tag_len,const char *_comment){
|
|||
}
|
||||
|
||||
const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
char **user_comments;
|
||||
size_t tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return NULL;
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci])){
|
||||
if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci])){
|
||||
/*We return a pointer to the data, not a copy.*/
|
||||
if(_count==found++)return user_comments[ci]+tag_len+1;
|
||||
}
|
||||
|
@ -368,17 +380,18 @@ const char *opus_tags_query(const OpusTags *_tags,const char *_tag,int _count){
|
|||
}
|
||||
|
||||
int opus_tags_query_count(const OpusTags *_tags,const char *_tag){
|
||||
char **user_comments;
|
||||
int tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
char **user_comments;
|
||||
size_t tag_len;
|
||||
int found;
|
||||
int ncomments;
|
||||
int ci;
|
||||
tag_len=strlen(_tag);
|
||||
if(OP_UNLIKELY(tag_len>(size_t)INT_MAX))return 0;
|
||||
ncomments=_tags->comments;
|
||||
user_comments=_tags->user_comments;
|
||||
found=0;
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(!opus_tagncompare(_tag,tag_len,user_comments[ci]))found++;
|
||||
if(!opus_tagncompare(_tag,(int)tag_len,user_comments[ci]))found++;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
@ -403,7 +416,8 @@ static int opus_tags_get_gain(const OpusTags *_tags,int *_gain_q8,
|
|||
ncomments=_tags->comments;
|
||||
/*Look for the first valid tag with the name _tag_name and use that.*/
|
||||
for(ci=0;ci<ncomments;ci++){
|
||||
if(opus_tagncompare(_tag_name,_tag_len,comments[ci])==0){
|
||||
OP_ASSERT(_tag_len<=(size_t)INT_MAX);
|
||||
if(opus_tagncompare(_tag_name,(int)_tag_len,comments[ci])==0){
|
||||
char *p;
|
||||
opus_int32 gain_q8;
|
||||
int negative;
|
||||
|
@ -439,8 +453,7 @@ int opus_tags_get_track_gain(const OpusTags *_tags,int *_gain_q8){
|
|||
}
|
||||
|
||||
static int op_is_jpeg(const unsigned char *_buf,size_t _buf_sz){
|
||||
return _buf_sz>=11&&memcmp(_buf,"\xFF\xD8\xFF\xE0",4)==0
|
||||
&&(_buf[4]<<8|_buf[5])>=16&&memcmp(_buf+6,"JFIF",5)==0;
|
||||
return _buf_sz>=3&&memcmp(_buf,"\xFF\xD8\xFF",3)==0;
|
||||
}
|
||||
|
||||
/*Tries to extract the width, height, bits per pixel, and palette size of a
|
||||
|
|
|
@ -136,6 +136,9 @@ struct OggOpusLink{
|
|||
that end-trimming calculations work properly.
|
||||
This is only valid for seekable sources.*/
|
||||
opus_int64 end_offset;
|
||||
/*The total duration of all prior links.
|
||||
This is always zero for non-seekable sources.*/
|
||||
ogg_int64_t pcm_file_offset;
|
||||
/*The granule position of the last sample.
|
||||
This is only valid for seekable sources.*/
|
||||
ogg_int64_t pcm_end;
|
||||
|
@ -150,23 +153,25 @@ struct OggOpusLink{
|
|||
};
|
||||
|
||||
struct OggOpusFile{
|
||||
/*The callbacks used to access the data source.*/
|
||||
/*The callbacks used to access the stream.*/
|
||||
OpusFileCallbacks callbacks;
|
||||
/*A FILE *, memory bufer, etc.*/
|
||||
void *source;
|
||||
/*Whether or not we can seek with this data source.*/
|
||||
/*A FILE *, memory buffer, etc.*/
|
||||
void *stream;
|
||||
/*Whether or not we can seek with this stream.*/
|
||||
int seekable;
|
||||
/*The number of links in this chained Ogg Opus file.*/
|
||||
int nlinks;
|
||||
/*The cached information from each link in a chained Ogg Opus file.
|
||||
If source isn't seekable (e.g., it's a pipe), only the current link
|
||||
If stream isn't seekable (e.g., it's a pipe), only the current link
|
||||
appears.*/
|
||||
OggOpusLink *links;
|
||||
/*The number of serial numbers from a single link.*/
|
||||
int nserialnos;
|
||||
/*The capacity of the list of serial numbers from a single link.*/
|
||||
int cserialnos;
|
||||
/*Storage for the list of serial numbers from a single link.*/
|
||||
/*Storage for the list of serial numbers from a single link.
|
||||
This is a scratch buffer used when scanning the BOS pages at the start of
|
||||
each link.*/
|
||||
ogg_uint32_t *serialnos;
|
||||
/*This is the current offset of the data processed by the ogg_sync_state.
|
||||
After a seek, this should be set to the target offset so that we can track
|
||||
|
@ -174,9 +179,9 @@ struct OggOpusFile{
|
|||
After a call to op_get_next_page(), this will point to the first byte after
|
||||
that page.*/
|
||||
opus_int64 offset;
|
||||
/*The total size of this data source, or -1 if it's unseekable.*/
|
||||
/*The total size of this stream, or -1 if it's unseekable.*/
|
||||
opus_int64 end;
|
||||
/*Used to locate pages in the data source.*/
|
||||
/*Used to locate pages in the stream.*/
|
||||
ogg_sync_state oy;
|
||||
/*One of OP_NOTOPEN, OP_PARTOPEN, OP_OPENED, OP_STREAMSET, OP_INITSET.*/
|
||||
int ready_state;
|
||||
|
@ -227,7 +232,7 @@ struct OggOpusFile{
|
|||
/*The number of valid samples in the decoded buffer.*/
|
||||
int od_buffer_size;
|
||||
/*The type of gain offset to apply.
|
||||
One of OP_HEADER_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
|
||||
One of OP_HEADER_GAIN, OP_ALBUM_GAIN, OP_TRACK_GAIN, or OP_ABSOLUTE_GAIN.*/
|
||||
int gain_type;
|
||||
/*The offset to apply to the gain.*/
|
||||
opus_int32 gain_offset_q8;
|
||||
|
|
|
@ -0,0 +1,378 @@
|
|||
/* Copyright (c) 2017 Google Inc.
|
||||
Written by Andrew Allen */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "arch.h"
|
||||
#include "float_cast.h"
|
||||
#include "opus_private.h"
|
||||
#include "opus_defines.h"
|
||||
#include "mapping_matrix.h"
|
||||
|
||||
#define MATRIX_INDEX(nb_rows, row, col) (nb_rows * col + row)
|
||||
|
||||
opus_int32 mapping_matrix_get_size(int rows, int cols)
|
||||
{
|
||||
opus_int32 size;
|
||||
|
||||
/* Mapping Matrix must only support up to 255 channels in or out.
|
||||
* Additionally, the total cell count must be <= 65004 octets in order
|
||||
* for the matrix to be stored in an OGG header.
|
||||
*/
|
||||
if (rows > 255 || cols > 255)
|
||||
return 0;
|
||||
size = rows * (opus_int32)cols * sizeof(opus_int16);
|
||||
if (size > 65004)
|
||||
return 0;
|
||||
|
||||
return align(sizeof(MappingMatrix)) + align(size);
|
||||
}
|
||||
|
||||
opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (opus_int16*)(void*)((char*)matrix + align(sizeof(MappingMatrix)));
|
||||
}
|
||||
|
||||
void mapping_matrix_init(MappingMatrix * const matrix,
|
||||
int rows, int cols, int gain, const opus_int16 *data, opus_int32 data_size)
|
||||
{
|
||||
int i;
|
||||
opus_int16 *ptr;
|
||||
|
||||
#if !defined(ENABLE_ASSERTIONS)
|
||||
(void)data_size;
|
||||
#endif
|
||||
celt_assert(align(data_size) == align(rows * cols * sizeof(opus_int16)));
|
||||
|
||||
matrix->rows = rows;
|
||||
matrix->cols = cols;
|
||||
matrix->gain = gain;
|
||||
ptr = mapping_matrix_get_data(matrix);
|
||||
for (i = 0; i < rows * cols; i++)
|
||||
{
|
||||
ptr[i] = data[i];
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
void mapping_matrix_multiply_channel_in_float(
|
||||
const MappingMatrix *matrix,
|
||||
const float *input,
|
||||
int input_rows,
|
||||
opus_val16 *output,
|
||||
int output_row,
|
||||
int output_rows,
|
||||
int frame_size)
|
||||
{
|
||||
/* Matrix data is ordered col-wise. */
|
||||
opus_int16* matrix_data;
|
||||
int i, col;
|
||||
|
||||
celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
|
||||
|
||||
matrix_data = mapping_matrix_get_data(matrix);
|
||||
|
||||
for (i = 0; i < frame_size; i++)
|
||||
{
|
||||
float tmp = 0;
|
||||
for (col = 0; col < input_rows; col++)
|
||||
{
|
||||
tmp +=
|
||||
matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
|
||||
input[MATRIX_INDEX(input_rows, col, i)];
|
||||
}
|
||||
#if defined(FIXED_POINT)
|
||||
output[output_rows * i] = FLOAT2INT16((1/32768.f)*tmp);
|
||||
#else
|
||||
output[output_rows * i] = (1/32768.f)*tmp;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void mapping_matrix_multiply_channel_out_float(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_val16 *input,
|
||||
int input_row,
|
||||
int input_rows,
|
||||
float *output,
|
||||
int output_rows,
|
||||
int frame_size
|
||||
)
|
||||
{
|
||||
/* Matrix data is ordered col-wise. */
|
||||
opus_int16* matrix_data;
|
||||
int i, row;
|
||||
float input_sample;
|
||||
|
||||
celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
|
||||
|
||||
matrix_data = mapping_matrix_get_data(matrix);
|
||||
|
||||
for (i = 0; i < frame_size; i++)
|
||||
{
|
||||
#if defined(FIXED_POINT)
|
||||
input_sample = (1/32768.f)*input[input_rows * i];
|
||||
#else
|
||||
input_sample = input[input_rows * i];
|
||||
#endif
|
||||
for (row = 0; row < output_rows; row++)
|
||||
{
|
||||
float tmp =
|
||||
(1/32768.f)*matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] *
|
||||
input_sample;
|
||||
output[MATRIX_INDEX(output_rows, row, i)] += tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
void mapping_matrix_multiply_channel_in_short(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_int16 *input,
|
||||
int input_rows,
|
||||
opus_val16 *output,
|
||||
int output_row,
|
||||
int output_rows,
|
||||
int frame_size)
|
||||
{
|
||||
/* Matrix data is ordered col-wise. */
|
||||
opus_int16* matrix_data;
|
||||
int i, col;
|
||||
|
||||
celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
|
||||
|
||||
matrix_data = mapping_matrix_get_data(matrix);
|
||||
|
||||
for (i = 0; i < frame_size; i++)
|
||||
{
|
||||
opus_val32 tmp = 0;
|
||||
for (col = 0; col < input_rows; col++)
|
||||
{
|
||||
#if defined(FIXED_POINT)
|
||||
tmp +=
|
||||
((opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
|
||||
(opus_int32)input[MATRIX_INDEX(input_rows, col, i)]) >> 8;
|
||||
#else
|
||||
tmp +=
|
||||
matrix_data[MATRIX_INDEX(matrix->rows, output_row, col)] *
|
||||
input[MATRIX_INDEX(input_rows, col, i)];
|
||||
#endif
|
||||
}
|
||||
#if defined(FIXED_POINT)
|
||||
output[output_rows * i] = (opus_int16)((tmp + 64) >> 7);
|
||||
#else
|
||||
output[output_rows * i] = (1/(32768.f*32768.f))*tmp;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void mapping_matrix_multiply_channel_out_short(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_val16 *input,
|
||||
int input_row,
|
||||
int input_rows,
|
||||
opus_int16 *output,
|
||||
int output_rows,
|
||||
int frame_size)
|
||||
{
|
||||
/* Matrix data is ordered col-wise. */
|
||||
opus_int16* matrix_data;
|
||||
int i, row;
|
||||
opus_int32 input_sample;
|
||||
|
||||
celt_assert(input_rows <= matrix->cols && output_rows <= matrix->rows);
|
||||
|
||||
matrix_data = mapping_matrix_get_data(matrix);
|
||||
|
||||
for (i = 0; i < frame_size; i++)
|
||||
{
|
||||
#if defined(FIXED_POINT)
|
||||
input_sample = (opus_int32)input[input_rows * i];
|
||||
#else
|
||||
input_sample = (opus_int32)FLOAT2INT16(input[input_rows * i]);
|
||||
#endif
|
||||
for (row = 0; row < output_rows; row++)
|
||||
{
|
||||
opus_int32 tmp =
|
||||
(opus_int32)matrix_data[MATRIX_INDEX(matrix->rows, row, input_row)] *
|
||||
input_sample;
|
||||
output[MATRIX_INDEX(output_rows, row, i)] += (tmp + 16384) >> 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const MappingMatrix mapping_matrix_foa_mixing = { 6, 6, 0 };
|
||||
const opus_int16 mapping_matrix_foa_mixing_data[36] = {
|
||||
16384, 0, -16384, 23170, 0, 0, 16384, 23170,
|
||||
16384, 0, 0, 0, 16384, 0, -16384, -23170,
|
||||
0, 0, 16384, -23170, 16384, 0, 0, 0,
|
||||
0, 0, 0, 0, 32767, 0, 0, 0,
|
||||
0, 0, 0, 32767
|
||||
};
|
||||
|
||||
const MappingMatrix mapping_matrix_soa_mixing = { 11, 11, 0 };
|
||||
const opus_int16 mapping_matrix_soa_mixing_data[121] = {
|
||||
10923, 7723, 13377, -13377, 11585, 9459, 7723, -16384,
|
||||
-6689, 0, 0, 10923, 7723, 13377, 13377, -11585,
|
||||
9459, 7723, 16384, -6689, 0, 0, 10923, -15447,
|
||||
13377, 0, 0, -18919, 7723, 0, 13377, 0,
|
||||
0, 10923, 7723, -13377, -13377, 11585, -9459, 7723,
|
||||
16384, -6689, 0, 0, 10923, -7723, 0, 13377,
|
||||
-16384, 0, -15447, 0, 9459, 0, 0, 10923,
|
||||
-7723, 0, -13377, 16384, 0, -15447, 0, 9459,
|
||||
0, 0, 10923, 15447, 0, 0, 0, 0,
|
||||
-15447, 0, -18919, 0, 0, 10923, 7723, -13377,
|
||||
13377, -11585, -9459, 7723, -16384, -6689, 0, 0,
|
||||
10923, -15447, -13377, 0, 0, 18919, 7723, 0,
|
||||
13377, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 32767, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32767
|
||||
};
|
||||
|
||||
const MappingMatrix mapping_matrix_toa_mixing = { 18, 18, 0 };
|
||||
const opus_int16 mapping_matrix_toa_mixing_data[324] = {
|
||||
8208, 0, -881, 14369, 0, 0, -8192, -4163,
|
||||
13218, 0, 0, 0, 11095, -8836, -6218, 14833,
|
||||
0, 0, 8208, -10161, 881, 10161, -13218, -2944,
|
||||
-8192, 2944, 0, -10488, -6218, 6248, -11095, -6248,
|
||||
0, -10488, 0, 0, 8208, 10161, 881, -10161,
|
||||
-13218, 2944, -8192, -2944, 0, 10488, -6218, -6248,
|
||||
-11095, 6248, 0, 10488, 0, 0, 8176, 5566,
|
||||
-11552, 5566, 9681, -11205, 8192, -11205, 0, 4920,
|
||||
-15158, 9756, -3334, 9756, 0, -4920, 0, 0,
|
||||
8176, 7871, 11552, 0, 0, 15846, 8192, 0,
|
||||
-9681, -6958, 0, 13797, 3334, 0, -15158, 0,
|
||||
0, 0, 8176, 0, 11552, 7871, 0, 0,
|
||||
8192, 15846, 9681, 0, 0, 0, 3334, 13797,
|
||||
15158, 6958, 0, 0, 8176, 5566, -11552, -5566,
|
||||
-9681, -11205, 8192, 11205, 0, 4920, 15158, 9756,
|
||||
-3334, -9756, 0, 4920, 0, 0, 8208, 14369,
|
||||
-881, 0, 0, -4163, -8192, 0, -13218, -14833,
|
||||
0, -8836, 11095, 0, 6218, 0, 0, 0,
|
||||
8208, 10161, 881, 10161, 13218, 2944, -8192, 2944,
|
||||
0, 10488, 6218, -6248, -11095, -6248, 0, -10488,
|
||||
0, 0, 8208, -14369, -881, 0, 0, 4163,
|
||||
-8192, 0, -13218, 14833, 0, 8836, 11095, 0,
|
||||
6218, 0, 0, 0, 8208, 0, -881, -14369,
|
||||
0, 0, -8192, 4163, 13218, 0, 0, 0,
|
||||
11095, 8836, -6218, -14833, 0, 0, 8176, -5566,
|
||||
-11552, 5566, -9681, 11205, 8192, -11205, 0, -4920,
|
||||
15158, -9756, -3334, 9756, 0, -4920, 0, 0,
|
||||
8176, 0, 11552, -7871, 0, 0, 8192, -15846,
|
||||
9681, 0, 0, 0, 3334, -13797, 15158, -6958,
|
||||
0, 0, 8176, -7871, 11552, 0, 0, -15846,
|
||||
8192, 0, -9681, 6958, 0, -13797, 3334, 0,
|
||||
-15158, 0, 0, 0, 8176, -5566, -11552, -5566,
|
||||
9681, 11205, 8192, 11205, 0, -4920, -15158, -9756,
|
||||
-3334, -9756, 0, 4920, 0, 0, 8208, -10161,
|
||||
881, -10161, 13218, -2944, -8192, -2944, 0, -10488,
|
||||
6218, 6248, -11095, 6248, 0, 10488, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32767, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 32767
|
||||
};
|
||||
|
||||
const MappingMatrix mapping_matrix_foa_demixing = { 6, 6, 0 };
|
||||
const opus_int16 mapping_matrix_foa_demixing_data[36] = {
|
||||
16384, 16384, 16384, 16384, 0, 0, 0, 23170,
|
||||
0, -23170, 0, 0, -16384, 16384, -16384, 16384,
|
||||
0, 0, 23170, 0, -23170, 0, 0, 0,
|
||||
0, 0, 0, 0, 32767, 0, 0, 0,
|
||||
0, 0, 0, 32767
|
||||
};
|
||||
|
||||
const MappingMatrix mapping_matrix_soa_demixing = { 11, 11, 3050 };
|
||||
const opus_int16 mapping_matrix_soa_demixing_data[121] = {
|
||||
2771, 2771, 2771, 2771, 2771, 2771, 2771, 2771,
|
||||
2771, 0, 0, 10033, 10033, -20066, 10033, 14189,
|
||||
14189, -28378, 10033, -20066, 0, 0, 3393, 3393,
|
||||
3393, -3393, 0, 0, 0, -3393, -3393, 0,
|
||||
0, -17378, 17378, 0, -17378, -24576, 24576, 0,
|
||||
17378, 0, 0, 0, -14189, 14189, 0, -14189,
|
||||
-28378, 28378, 0, 14189, 0, 0, 0, 2399,
|
||||
2399, -4799, -2399, 0, 0, 0, -2399, 4799,
|
||||
0, 0, 1959, 1959, 1959, 1959, -3918, -3918,
|
||||
-3918, 1959, 1959, 0, 0, -4156, 4156, 0,
|
||||
4156, 0, 0, 0, -4156, 0, 0, 0,
|
||||
8192, 8192, -16384, 8192, 16384, 16384, -32768, 8192,
|
||||
-16384, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 8312, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
8312
|
||||
};
|
||||
|
||||
const MappingMatrix mapping_matrix_toa_demixing = { 18, 18, 0 };
|
||||
const opus_int16 mapping_matrix_toa_demixing_data[324] = {
|
||||
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
|
||||
8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
|
||||
0, 0, 0, -9779, 9779, 6263, 8857, 0,
|
||||
6263, 13829, 9779, -13829, 0, -6263, 0, -8857,
|
||||
-6263, -9779, 0, 0, -3413, 3413, 3413, -11359,
|
||||
11359, 11359, -11359, -3413, 3413, -3413, -3413, -11359,
|
||||
11359, 11359, -11359, 3413, 0, 0, 13829, 9779,
|
||||
-9779, 6263, 0, 8857, -6263, 0, 9779, 0,
|
||||
-13829, 6263, -8857, 0, -6263, -9779, 0, 0,
|
||||
0, -15617, -15617, 6406, 0, 0, -6406, 0,
|
||||
15617, 0, 0, -6406, 0, 0, 6406, 15617,
|
||||
0, 0, 0, -5003, 5003, -10664, 15081, 0,
|
||||
-10664, -7075, 5003, 7075, 0, 10664, 0, -15081,
|
||||
10664, -5003, 0, 0, -8176, -8176, -8176, 8208,
|
||||
8208, 8208, 8208, -8176, -8176, -8176, -8176, 8208,
|
||||
8208, 8208, 8208, -8176, 0, 0, -7075, 5003,
|
||||
-5003, -10664, 0, 15081, 10664, 0, 5003, 0,
|
||||
7075, -10664, -15081, 0, 10664, -5003, 0, 0,
|
||||
15617, 0, 0, 0, -6406, 6406, 0, -15617,
|
||||
0, -15617, 15617, 0, 6406, -6406, 0, 0,
|
||||
0, 0, 0, -11393, 11393, 2993, -4233, 0,
|
||||
2993, -16112, 11393, 16112, 0, -2993, 0, 4233,
|
||||
-2993, -11393, 0, 0, 0, -9974, -9974, -13617,
|
||||
0, 0, 13617, 0, 9974, 0, 0, 13617,
|
||||
0, 0, -13617, 9974, 0, 0, 0, 5579,
|
||||
-5579, 10185, 14403, 0, 10185, -7890, -5579, 7890,
|
||||
0, -10185, 0, -14403, -10185, 5579, 0, 0,
|
||||
11826, -11826, -11826, -901, 901, 901, -901, 11826,
|
||||
-11826, 11826, 11826, -901, 901, 901, -901, -11826,
|
||||
0, 0, -7890, -5579, 5579, 10185, 0, 14403,
|
||||
-10185, 0, -5579, 0, 7890, 10185, -14403, 0,
|
||||
-10185, 5579, 0, 0, -9974, 0, 0, 0,
|
||||
-13617, 13617, 0, 9974, 0, 9974, -9974, 0,
|
||||
13617, -13617, 0, 0, 0, 0, 16112, -11393,
|
||||
11393, -2993, 0, 4233, 2993, 0, -11393, 0,
|
||||
-16112, -2993, -4233, 0, 2993, 11393, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
32767, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 32767
|
||||
};
|
||||
|
|
@ -0,0 +1,133 @@
|
|||
/* Copyright (c) 2017 Google Inc.
|
||||
Written by Andrew Allen */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file mapping_matrix.h
|
||||
* @brief Opus reference implementation mapping matrix API
|
||||
*/
|
||||
|
||||
#ifndef MAPPING_MATRIX_H
|
||||
#define MAPPING_MATRIX_H
|
||||
|
||||
#include "opus_types.h"
|
||||
#include "opus_projection.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct MappingMatrix
|
||||
{
|
||||
int rows; /* number of channels outputted from matrix. */
|
||||
int cols; /* number of channels inputted to matrix. */
|
||||
int gain; /* in dB. S7.8-format. */
|
||||
/* Matrix cell data goes here using col-wise ordering. */
|
||||
} MappingMatrix;
|
||||
|
||||
opus_int32 mapping_matrix_get_size(int rows, int cols);
|
||||
|
||||
opus_int16 *mapping_matrix_get_data(const MappingMatrix *matrix);
|
||||
|
||||
void mapping_matrix_init(
|
||||
MappingMatrix * const matrix,
|
||||
int rows,
|
||||
int cols,
|
||||
int gain,
|
||||
const opus_int16 *data,
|
||||
opus_int32 data_size
|
||||
);
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
void mapping_matrix_multiply_channel_in_float(
|
||||
const MappingMatrix *matrix,
|
||||
const float *input,
|
||||
int input_rows,
|
||||
opus_val16 *output,
|
||||
int output_row,
|
||||
int output_rows,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
void mapping_matrix_multiply_channel_out_float(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_val16 *input,
|
||||
int input_row,
|
||||
int input_rows,
|
||||
float *output,
|
||||
int output_rows,
|
||||
int frame_size
|
||||
);
|
||||
#endif /* DISABLE_FLOAT_API */
|
||||
|
||||
void mapping_matrix_multiply_channel_in_short(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_int16 *input,
|
||||
int input_rows,
|
||||
opus_val16 *output,
|
||||
int output_row,
|
||||
int output_rows,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
void mapping_matrix_multiply_channel_out_short(
|
||||
const MappingMatrix *matrix,
|
||||
const opus_val16 *input,
|
||||
int input_row,
|
||||
int input_rows,
|
||||
opus_int16 *output,
|
||||
int output_rows,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
/* Pre-computed mixing and demixing matrices for 1st to 3rd-order ambisonics.
|
||||
* foa: first-order ambisonics
|
||||
* soa: second-order ambisonics
|
||||
* toa: third-order ambisonics
|
||||
*/
|
||||
extern const MappingMatrix mapping_matrix_foa_mixing;
|
||||
extern const opus_int16 mapping_matrix_foa_mixing_data[36];
|
||||
|
||||
extern const MappingMatrix mapping_matrix_soa_mixing;
|
||||
extern const opus_int16 mapping_matrix_soa_mixing_data[121];
|
||||
|
||||
extern const MappingMatrix mapping_matrix_toa_mixing;
|
||||
extern const opus_int16 mapping_matrix_toa_mixing_data[324];
|
||||
|
||||
extern const MappingMatrix mapping_matrix_foa_demixing;
|
||||
extern const opus_int16 mapping_matrix_foa_demixing_data[36];
|
||||
|
||||
extern const MappingMatrix mapping_matrix_soa_demixing;
|
||||
extern const opus_int16 mapping_matrix_soa_demixing_data[121];
|
||||
|
||||
extern const MappingMatrix mapping_matrix_toa_demixing;
|
||||
extern const opus_int16 mapping_matrix_toa_demixing_data[324];
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* MAPPING_MATRIX_H */
|
|
@ -1,5 +1,5 @@
|
|||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Written by Jean-Marc Valin */
|
||||
2012-2017 Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -29,42 +29,13 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <math.h>
|
||||
#include "opus_types.h"
|
||||
#include "opus_defines.h"
|
||||
|
||||
#include <math.h>
|
||||
#include "mlp.h"
|
||||
#include "arch.h"
|
||||
#include "tansig_table.h"
|
||||
#define MAX_NEURONS 100
|
||||
#include "mlp.h"
|
||||
|
||||
#if 0
|
||||
static OPUS_INLINE opus_val16 tansig_approx(opus_val32 _x) /* Q19 */
|
||||
{
|
||||
int i;
|
||||
opus_val16 xx; /* Q11 */
|
||||
/*double x, y;*/
|
||||
opus_val16 dy, yy; /* Q14 */
|
||||
/*x = 1.9073e-06*_x;*/
|
||||
if (_x>=QCONST32(8,19))
|
||||
return QCONST32(1.,14);
|
||||
if (_x<=-QCONST32(8,19))
|
||||
return -QCONST32(1.,14);
|
||||
xx = EXTRACT16(SHR32(_x, 8));
|
||||
/*i = lrint(25*x);*/
|
||||
i = SHR32(ADD32(1024,MULT16_16(25, xx)),11);
|
||||
/*x -= .04*i;*/
|
||||
xx -= EXTRACT16(SHR32(MULT16_16(20972,i),8));
|
||||
/*x = xx*(1./2048);*/
|
||||
/*y = tansig_table[250+i];*/
|
||||
yy = tansig_table[250+i];
|
||||
/*y = yy*(1./16384);*/
|
||||
dy = 16384-MULT16_16_Q14(yy,yy);
|
||||
yy = yy + MULT16_16_Q14(MULT16_16_Q11(xx,dy),(16384 - MULT16_16_Q11(yy,xx)));
|
||||
return yy;
|
||||
}
|
||||
#else
|
||||
/*extern const float tansig_table[501];*/
|
||||
static OPUS_INLINE float tansig_approx(float x)
|
||||
{
|
||||
int i;
|
||||
|
@ -92,54 +63,82 @@ static OPUS_INLINE float tansig_approx(float x)
|
|||
y = y + x*dy*(1 - y*x);
|
||||
return sign*y;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
void mlp_process(const MLP *m, const opus_val16 *in, opus_val16 *out)
|
||||
static OPUS_INLINE float sigmoid_approx(float x)
|
||||
{
|
||||
int j;
|
||||
opus_val16 hidden[MAX_NEURONS];
|
||||
const opus_val16 *W = m->weights;
|
||||
/* Copy to tmp_in */
|
||||
for (j=0;j<m->topo[1];j++)
|
||||
{
|
||||
int k;
|
||||
opus_val32 sum = SHL32(EXTEND32(*W++),8);
|
||||
for (k=0;k<m->topo[0];k++)
|
||||
sum = MAC16_16(sum, in[k],*W++);
|
||||
hidden[j] = tansig_approx(sum);
|
||||
}
|
||||
for (j=0;j<m->topo[2];j++)
|
||||
{
|
||||
int k;
|
||||
opus_val32 sum = SHL32(EXTEND32(*W++),14);
|
||||
for (k=0;k<m->topo[1];k++)
|
||||
sum = MAC16_16(sum, hidden[k], *W++);
|
||||
out[j] = tansig_approx(EXTRACT16(PSHR32(sum,17)));
|
||||
}
|
||||
return .5f + .5f*tansig_approx(.5f*x);
|
||||
}
|
||||
#else
|
||||
void mlp_process(const MLP *m, const float *in, float *out)
|
||||
|
||||
static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x)
|
||||
{
|
||||
int j;
|
||||
float hidden[MAX_NEURONS];
|
||||
const float *W = m->weights;
|
||||
/* Copy to tmp_in */
|
||||
for (j=0;j<m->topo[1];j++)
|
||||
{
|
||||
int k;
|
||||
float sum = *W++;
|
||||
for (k=0;k<m->topo[0];k++)
|
||||
sum = sum + in[k]**W++;
|
||||
hidden[j] = tansig_approx(sum);
|
||||
}
|
||||
for (j=0;j<m->topo[2];j++)
|
||||
{
|
||||
int k;
|
||||
float sum = *W++;
|
||||
for (k=0;k<m->topo[1];k++)
|
||||
sum = sum + hidden[k]**W++;
|
||||
out[j] = tansig_approx(sum);
|
||||
}
|
||||
int i, j;
|
||||
for (i=0;i<rows;i++)
|
||||
{
|
||||
for (j=0;j<cols;j++)
|
||||
out[i] += weights[j*col_stride + i]*x[j];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void compute_dense(const DenseLayer *layer, float *output, const float *input)
|
||||
{
|
||||
int i;
|
||||
int N, M;
|
||||
int stride;
|
||||
M = layer->nb_inputs;
|
||||
N = layer->nb_neurons;
|
||||
stride = N;
|
||||
for (i=0;i<N;i++)
|
||||
output[i] = layer->bias[i];
|
||||
gemm_accum(output, layer->input_weights, N, M, stride, input);
|
||||
for (i=0;i<N;i++)
|
||||
output[i] *= WEIGHTS_SCALE;
|
||||
if (layer->sigmoid) {
|
||||
for (i=0;i<N;i++)
|
||||
output[i] = sigmoid_approx(output[i]);
|
||||
} else {
|
||||
for (i=0;i<N;i++)
|
||||
output[i] = tansig_approx(output[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void compute_gru(const GRULayer *gru, float *state, const float *input)
|
||||
{
|
||||
int i;
|
||||
int N, M;
|
||||
int stride;
|
||||
float tmp[MAX_NEURONS];
|
||||
float z[MAX_NEURONS];
|
||||
float r[MAX_NEURONS];
|
||||
float h[MAX_NEURONS];
|
||||
M = gru->nb_inputs;
|
||||
N = gru->nb_neurons;
|
||||
stride = 3*N;
|
||||
/* Compute update gate. */
|
||||
for (i=0;i<N;i++)
|
||||
z[i] = gru->bias[i];
|
||||
gemm_accum(z, gru->input_weights, N, M, stride, input);
|
||||
gemm_accum(z, gru->recurrent_weights, N, N, stride, state);
|
||||
for (i=0;i<N;i++)
|
||||
z[i] = sigmoid_approx(WEIGHTS_SCALE*z[i]);
|
||||
|
||||
/* Compute reset gate. */
|
||||
for (i=0;i<N;i++)
|
||||
r[i] = gru->bias[N + i];
|
||||
gemm_accum(r, &gru->input_weights[N], N, M, stride, input);
|
||||
gemm_accum(r, &gru->recurrent_weights[N], N, N, stride, state);
|
||||
for (i=0;i<N;i++)
|
||||
r[i] = sigmoid_approx(WEIGHTS_SCALE*r[i]);
|
||||
|
||||
/* Compute output. */
|
||||
for (i=0;i<N;i++)
|
||||
h[i] = gru->bias[2*N + i];
|
||||
for (i=0;i<N;i++)
|
||||
tmp[i] = state[i] * r[i];
|
||||
gemm_accum(h, &gru->input_weights[2*N], N, M, stride, input);
|
||||
gemm_accum(h, &gru->recurrent_weights[2*N], N, N, stride, tmp);
|
||||
for (i=0;i<N;i++)
|
||||
h[i] = z[i]*state[i] + (1-z[i])*tansig_approx(WEIGHTS_SCALE*h[i]);
|
||||
for (i=0;i<N;i++)
|
||||
state[i] = h[i];
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* Copyright (c) 2008-2011 Octasic Inc.
|
||||
Written by Jean-Marc Valin */
|
||||
/* Copyright (c) 2017 Jean-Marc Valin */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
|
@ -28,16 +27,34 @@
|
|||
#ifndef _MLP_H_
|
||||
#define _MLP_H_
|
||||
|
||||
#include "arch.h"
|
||||
#include "opus_types.h"
|
||||
|
||||
#define WEIGHTS_SCALE (1.f/128)
|
||||
|
||||
#define MAX_NEURONS 32
|
||||
|
||||
typedef struct {
|
||||
int layers;
|
||||
const int *topo;
|
||||
const float *weights;
|
||||
} MLP;
|
||||
const opus_int8 *bias;
|
||||
const opus_int8 *input_weights;
|
||||
int nb_inputs;
|
||||
int nb_neurons;
|
||||
int sigmoid;
|
||||
} DenseLayer;
|
||||
|
||||
extern const MLP net;
|
||||
typedef struct {
|
||||
const opus_int8 *bias;
|
||||
const opus_int8 *input_weights;
|
||||
const opus_int8 *recurrent_weights;
|
||||
int nb_inputs;
|
||||
int nb_neurons;
|
||||
} GRULayer;
|
||||
|
||||
void mlp_process(const MLP *m, const float *in, float *out);
|
||||
extern const DenseLayer layer0;
|
||||
extern const GRULayer layer1;
|
||||
extern const DenseLayer layer2;
|
||||
|
||||
void compute_dense(const DenseLayer *layer, float *output, const float *input);
|
||||
|
||||
void compute_gru(const GRULayer *gru, float *state, const float *input);
|
||||
|
||||
#endif /* _MLP_H_ */
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* The contents of this file was automatically generated by mlp_train.c
|
||||
It contains multi-layer perceptron (MLP) weights. */
|
||||
/*This file is automatically generated from a Keras model*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
|
@ -7,103 +6,667 @@
|
|||
|
||||
#include "mlp.h"
|
||||
|
||||
/* RMS error was 0.138320, seed was 1361535663 */
|
||||
|
||||
static const float weights[422] = {
|
||||
|
||||
/* hidden layer */
|
||||
-0.0941125f, -0.302976f, -0.603555f, -0.19393f, -0.185983f,
|
||||
-0.601617f, -0.0465317f, -0.114563f, -0.103599f, -0.618938f,
|
||||
-0.317859f, -0.169949f, -0.0702885f, 0.148065f, 0.409524f,
|
||||
0.548432f, 0.367649f, -0.494393f, 0.764306f, -1.83957f,
|
||||
0.170849f, 12.786f, -1.08848f, -1.27284f, -16.2606f,
|
||||
24.1773f, -5.57454f, -0.17276f, -0.163388f, -0.224421f,
|
||||
-0.0948944f, -0.0728695f, -0.26557f, -0.100283f, -0.0515459f,
|
||||
-0.146142f, -0.120674f, -0.180655f, 0.12857f, 0.442138f,
|
||||
-0.493735f, 0.167767f, 0.206699f, -0.197567f, 0.417999f,
|
||||
1.50364f, -0.773341f, -10.0401f, 0.401872f, 2.97966f,
|
||||
15.2165f, -1.88905f, -1.19254f, 0.0285397f, -0.00405139f,
|
||||
0.0707565f, 0.00825699f, -0.0927269f, -0.010393f, -0.00428882f,
|
||||
-0.00489743f, -0.0709731f, -0.00255992f, 0.0395619f, 0.226424f,
|
||||
0.0325231f, 0.162175f, -0.100118f, 0.485789f, 0.12697f,
|
||||
0.285937f, 0.0155637f, 0.10546f, 3.05558f, 1.15059f,
|
||||
-1.00904f, -1.83088f, 3.31766f, -3.42516f, -0.119135f,
|
||||
-0.0405654f, 0.00690068f, 0.0179877f, -0.0382487f, 0.00597941f,
|
||||
-0.0183611f, 0.00190395f, -0.144322f, -0.0435671f, 0.000990594f,
|
||||
0.221087f, 0.142405f, 0.484066f, 0.404395f, 0.511955f,
|
||||
-0.237255f, 0.241742f, 0.35045f, -0.699428f, 10.3993f,
|
||||
2.6507f, -2.43459f, -4.18838f, 1.05928f, 1.71067f,
|
||||
0.00667811f, -0.0721335f, -0.0397346f, 0.0362704f, -0.11496f,
|
||||
-0.0235776f, 0.0082161f, -0.0141741f, -0.0329699f, -0.0354253f,
|
||||
0.00277404f, -0.290654f, -1.14767f, -0.319157f, -0.686544f,
|
||||
0.36897f, 0.478899f, 0.182579f, -0.411069f, 0.881104f,
|
||||
-4.60683f, 1.4697f, 0.335845f, -1.81905f, -30.1699f,
|
||||
5.55225f, 0.0019508f, -0.123576f, -0.0727332f, -0.0641597f,
|
||||
-0.0534458f, -0.108166f, -0.0937368f, -0.0697883f, -0.0275475f,
|
||||
-0.192309f, -0.110074f, 0.285375f, -0.405597f, 0.0926724f,
|
||||
-0.287881f, -0.851193f, -0.099493f, -0.233764f, -1.2852f,
|
||||
1.13611f, 3.12168f, -0.0699f, -1.86216f, 2.65292f,
|
||||
-7.31036f, 2.44776f, -0.00111802f, -0.0632786f, -0.0376296f,
|
||||
-0.149851f, 0.142963f, 0.184368f, 0.123433f, 0.0756158f,
|
||||
0.117312f, 0.0933395f, 0.0692163f, 0.0842592f, 0.0704683f,
|
||||
0.0589963f, 0.0942205f, -0.448862f, 0.0262677f, 0.270352f,
|
||||
-0.262317f, 0.172586f, 2.00227f, -0.159216f, 0.038422f,
|
||||
10.2073f, 4.15536f, -2.3407f, -0.0550265f, 0.00964792f,
|
||||
-0.141336f, 0.0274501f, 0.0343921f, -0.0487428f, 0.0950172f,
|
||||
-0.00775017f, -0.0372492f, -0.00548121f, -0.0663695f, 0.0960506f,
|
||||
-0.200008f, -0.0412827f, 0.58728f, 0.0515787f, 0.337254f,
|
||||
0.855024f, 0.668371f, -0.114904f, -3.62962f, -0.467477f,
|
||||
-0.215472f, 2.61537f, 0.406117f, -1.36373f, 0.0425394f,
|
||||
0.12208f, 0.0934502f, 0.123055f, 0.0340935f, -0.142466f,
|
||||
0.035037f, -0.0490666f, 0.0733208f, 0.0576672f, 0.123984f,
|
||||
-0.0517194f, -0.253018f, 0.590565f, 0.145849f, 0.315185f,
|
||||
0.221534f, -0.149081f, 0.216161f, -0.349575f, 24.5664f,
|
||||
-0.994196f, 0.614289f, -18.7905f, -2.83277f, -0.716801f,
|
||||
-0.347201f, 0.479515f, -0.246027f, 0.0758683f, 0.137293f,
|
||||
-0.17781f, 0.118751f, -0.00108329f, -0.237334f, 0.355732f,
|
||||
-0.12991f, -0.0547627f, -0.318576f, -0.325524f, 0.180494f,
|
||||
-0.0625604f, 0.141219f, 0.344064f, 0.37658f, -0.591772f,
|
||||
5.8427f, -0.38075f, 0.221894f, -1.41934f, -1.87943e+06f,
|
||||
1.34114f, 0.0283355f, -0.0447856f, -0.0211466f, -0.0256927f,
|
||||
0.0139618f, 0.0207934f, -0.0107666f, 0.0110969f, 0.0586069f,
|
||||
-0.0253545f, -0.0328433f, 0.11872f, -0.216943f, 0.145748f,
|
||||
0.119808f, -0.0915211f, -0.120647f, -0.0787719f, -0.143644f,
|
||||
-0.595116f, -1.152f, -1.25335f, -1.17092f, 4.34023f,
|
||||
-975268.f, -1.37033f, -0.0401123f, 0.210602f, -0.136656f,
|
||||
0.135962f, -0.0523293f, 0.0444604f, 0.0143928f, 0.00412666f,
|
||||
-0.0193003f, 0.218452f, -0.110204f, -2.02563f, 0.918238f,
|
||||
-2.45362f, 1.19542f, -0.061362f, -1.92243f, 0.308111f,
|
||||
0.49764f, 0.912356f, 0.209272f, -2.34525f, 2.19326f,
|
||||
-6.47121f, 1.69771f, -0.725123f, 0.0118929f, 0.0377944f,
|
||||
0.0554003f, 0.0226452f, -0.0704421f, -0.0300309f, 0.0122978f,
|
||||
-0.0041782f, -0.0686612f, 0.0313115f, 0.039111f, 0.364111f,
|
||||
-0.0945548f, 0.0229876f, -0.17414f, 0.329795f, 0.114714f,
|
||||
0.30022f, 0.106997f, 0.132355f, 5.79932f, 0.908058f,
|
||||
-0.905324f, -3.3561f, 0.190647f, 0.184211f, -0.673648f,
|
||||
0.231807f, -0.0586222f, 0.230752f, -0.438277f, 0.245857f,
|
||||
-0.17215f, 0.0876383f, -0.720512f, 0.162515f, 0.0170571f,
|
||||
0.101781f, 0.388477f, 1.32931f, 1.08548f, -0.936301f,
|
||||
-2.36958f, -6.71988f, -3.44376f, 2.13818f, 14.2318f,
|
||||
4.91459f, -3.09052f, -9.69191f, -0.768234f, 1.79604f,
|
||||
0.0549653f, 0.163399f, 0.0797025f, 0.0343933f, -0.0555876f,
|
||||
-0.00505673f, 0.0187258f, 0.0326628f, 0.0231486f, 0.15573f,
|
||||
0.0476223f, -0.254824f, 1.60155f, -0.801221f, 2.55496f,
|
||||
0.737629f, -1.36249f, -0.695463f, -2.44301f, -1.73188f,
|
||||
3.95279f, 1.89068f, 0.486087f, -11.3343f, 3.9416e+06f,
|
||||
|
||||
/* output layer */
|
||||
-0.381439f, 0.12115f, -0.906927f, 2.93878f, 1.6388f,
|
||||
0.882811f, 0.874344f, 1.21726f, -0.874545f, 0.321706f,
|
||||
0.785055f, 0.946558f, -0.575066f, -3.46553f, 0.884905f,
|
||||
0.0924047f, -9.90712f, 0.391338f, 0.160103f, -2.04954f,
|
||||
4.1455f, 0.0684029f, -0.144761f, -0.285282f, 0.379244f,
|
||||
-1.1584f, -0.0277241f, -9.85f, -4.82386f, 3.71333f,
|
||||
3.87308f, 3.52558f};
|
||||
|
||||
static const int topo[3] = {25, 15, 2};
|
||||
|
||||
const MLP net = {
|
||||
3,
|
||||
topo,
|
||||
weights
|
||||
static const opus_int8 layer0_weights[800] = {
|
||||
-30, -9, 2, -12, 5, -1, 8, 9,
|
||||
9, 8, -13, 18, -17, -34, -5, 17,
|
||||
-11, 0, -4, 10, 2, 10, 15, -8,
|
||||
2, -1, 0, 5, 13, -3, -16, 1,
|
||||
-5, 3, 7, -28, -13, 6, 36, -3,
|
||||
19, -60, -17, -28, 7, -11, -30, -7,
|
||||
2, -42, -21, -3, 6, -22, 33, -9,
|
||||
7, -30, 21, -14, 24, -11, -20, -18,
|
||||
-5, -12, 12, -49, -50, -49, 16, 9,
|
||||
-37, -1, 9, 34, -13, -31, -31, 12,
|
||||
16, 44, -42, 2, -9, 8, -18, -6,
|
||||
9, 36, 19, 11, 13, 12, -21, 3,
|
||||
-28, -12, 3, 33, 25, -14, 11, 1,
|
||||
-94, -39, 18, -12, -11, -15, -7, 49,
|
||||
52, 10, -43, 9, 57, 8, 21, -6,
|
||||
14, -15, 44, -8, 7, -30, -13, -2,
|
||||
-9, 25, -2, -127, 18, -11, -52, 26,
|
||||
-27, 27, 10, -10, 7, 43, 6, -24,
|
||||
41, 10, -18, -27, 10, 17, 9, 10,
|
||||
-17, -10, 20, -6, 22, 55, 35, -80,
|
||||
36, 25, -24, -36, 15, 9, -19, 88,
|
||||
19, 64, -51, -35, 17, 0, -7, 41,
|
||||
-16, 27, 4, 15, -1, 18, -16, 47,
|
||||
-39, -54, -8, 13, -25, -20, 102, -18,
|
||||
-5, 44, 11, -28, 71, 2, -51, -5,
|
||||
5, 2, -83, -9, -29, 8, 21, -53,
|
||||
58, -37, -7, 13, 38, 9, 34, -1,
|
||||
-41, 21, 4, -24, -36, -33, -21, 32,
|
||||
75, -2, 1, -68, -1, 47, -29, 32,
|
||||
20, 12, -65, -87, 5, 16, -12, 24,
|
||||
40, 15, 7, 19, -26, -17, 17, 6,
|
||||
-2, -37, -30, -9, 32, -127, -39, 0,
|
||||
-31, -27, 4, -22, 23, -6, -77, 35,
|
||||
-61, 32, -37, -24, 13, -11, -1, -40,
|
||||
-3, 17, -7, 13, 11, 59, -19, 10,
|
||||
6, -18, 0, 13, 3, -6, -23, 19,
|
||||
11, -17, 13, -1, -80, 40, -53, 69,
|
||||
-29, -54, 0, -4, 33, -25, -2, 38,
|
||||
35, 36, -15, 46, 2, -13, -16, -8,
|
||||
-8, 12, -24, -9, -55, -5, -9, 32,
|
||||
11, 7, 12, -18, -10, -86, -38, 54,
|
||||
37, -25, 18, -43, 7, -27, -27, -54,
|
||||
13, 9, 22, 70, 6, 35, -7, 23,
|
||||
-15, -44, -6, 7, -66, -85, 32, 40,
|
||||
-19, -9, -7, 12, -15, 7, 2, 6,
|
||||
-35, 11, 28, 0, 26, 14, 1, 1,
|
||||
4, 12, 18, 35, 22, -18, -3, 14,
|
||||
-1, 7, 14, -8, -14, -3, 4, -3,
|
||||
-19, -7, -1, -25, -27, 25, -26, -2,
|
||||
33, -22, -27, -25, 4, -9, 7, 21,
|
||||
26, -30, 10, -9, -20, 11, 27, 10,
|
||||
5, -18, 14, -4, 2, -17, -5, -7,
|
||||
-9, -13, 15, 29, 1, -10, -16, -10,
|
||||
35, 36, -7, -22, -44, 17, 30, 22,
|
||||
21, -1, 22, -11, 32, -8, -7, 5,
|
||||
-10, 5, 30, -20, 29, -20, -34, 12,
|
||||
-4, -6, 6, -13, 10, -5, -68, -1,
|
||||
24, 9, 19, -24, -64, 31, 19, 27,
|
||||
-26, 75, -45, 41, 39, -42, 8, 6,
|
||||
23, -30, 16, -25, 30, 34, 8, -38,
|
||||
-3, 18, 16, -31, 22, -4, -9, 1,
|
||||
20, 9, 38, -32, 0, -45, 0, -6,
|
||||
-13, 11, -25, -32, -22, 31, -24, -11,
|
||||
-11, -4, -4, 20, -34, 22, 20, 9,
|
||||
-25, 27, -5, 28, -29, 29, 6, 21,
|
||||
-6, -18, 54, 4, -46, 23, 21, -14,
|
||||
-31, 36, -41, -24, 4, 22, 10, 11,
|
||||
7, 36, -32, -13, -52, -17, 24, 28,
|
||||
-37, -36, -1, 24, 9, -38, 35, 48,
|
||||
18, 2, -1, 45, 10, 39, 24, -38,
|
||||
13, 8, -16, 8, 25, 11, 7, -29,
|
||||
-11, 7, 20, -30, -38, -45, 14, -18,
|
||||
-28, -9, 65, 61, 22, -53, -38, -16,
|
||||
36, 46, 20, -39, 32, -61, -6, -6,
|
||||
-36, -33, -18, -28, 56, 101, 45, 11,
|
||||
-28, -23, -29, -61, 20, -47, 2, 48,
|
||||
27, -17, 1, 40, 1, 3, -51, 15,
|
||||
35, 28, 22, 35, 53, -61, -29, 12,
|
||||
-6, -21, 10, 3, -20, 2, -25, 1,
|
||||
-6, 31, 11, -3, 1, -10, -52, 6,
|
||||
126, -105, 122, 127, -128, 127, 127, -128,
|
||||
127, 108, 12, 127, 48, -128, -36, -128,
|
||||
127, 127, -128, -128, 127, 89, -128, 127,
|
||||
-128, -128, -128, 127, 127, -128, -128, -93,
|
||||
-82, 20, 125, 65, -82, 127, 38, -74,
|
||||
81, 88, -88, 79, 51, -47, -111, -26,
|
||||
14, 83, -88, -112, 24, 35, -101, 98,
|
||||
-99, -48, -45, 46, 83, -60, -79, 45,
|
||||
-20, -41, 9, 4, 52, 54, 93, -10,
|
||||
4, 13, 3, 123, 6, 94, -111, -69,
|
||||
-14, -31, 10, 12, 53, -79, -11, -21,
|
||||
-2, -44, -72, 92, 65, -57, 56, -38,
|
||||
127, -56, -128, 127, 127, -128, 86, 117,
|
||||
-75, -128, 127, -19, -99, -112, 127, -128,
|
||||
127, -48, 114, 118, -128, -128, 117, -17,
|
||||
-6, 121, -128, 127, -128, 82, 54, -106,
|
||||
127, 127, -33, 100, -39, -23, 18, -78,
|
||||
-34, -29, -1, -30, 127, -26, 127, -128,
|
||||
126, -128, 27, -23, -79, -120, -127, 127,
|
||||
72, 66, 29, 7, -66, -56, -117, -128
|
||||
};
|
||||
|
||||
static const opus_int8 layer0_bias[32] = {
|
||||
51, -16, 1, 13, -5, -6, -16, -7,
|
||||
11, -6, 106, 26, 28, -14, 21, -29,
|
||||
7, 18, -18, -17, 21, -17, -9, 20,
|
||||
-25, -3, -34, 48, 11, -13, -31, -20
|
||||
};
|
||||
|
||||
static const opus_int8 layer1_weights[2304] = {
|
||||
22, -1, -7, 7, 29, -27, -31, -17,
|
||||
-13, 33, 44, -8, 11, 33, 24, 78,
|
||||
15, 19, 30, -2, -24, 5, 49, 5,
|
||||
36, 29, -14, -11, -48, -33, 21, -42,
|
||||
-38, -12, 55, -37, 54, -8, 1, 36,
|
||||
17, 0, 51, 31, 59, 7, -12, 53,
|
||||
4, 32, -14, 48, 5, -10, -16, -8,
|
||||
1, -16, -56, -24, -6, 18, -2, 23,
|
||||
6, 46, -6, -10, 20, 35, -44, -15,
|
||||
-49, 36, 16, 5, -7, -79, -67, 12,
|
||||
70, -3, -79, -54, -85, -24, 47, -22,
|
||||
33, 21, 69, -1, 11, 22, 14, -16,
|
||||
-16, -22, -28, -11, 11, -41, 31, -26,
|
||||
-33, -19, -4, 27, 32, -50, 5, -10,
|
||||
-38, -22, -8, 35, -31, 1, -41, -15,
|
||||
-11, 44, 28, -17, -41, -23, 17, 2,
|
||||
-23, -26, -13, -13, -17, 6, 14, -31,
|
||||
-25, 9, -19, 39, -8, 4, 31, -1,
|
||||
-45, -11, -28, -92, -46, -15, 21, 118,
|
||||
-22, 45, -51, 11, -20, -20, -15, 13,
|
||||
-21, -97, -29, -32, -23, -42, 94, 1,
|
||||
23, -8, 63, -3, -46, 19, -26, 32,
|
||||
-40, -74, -26, 26, -4, -13, 30, -20,
|
||||
-30, -25, -14, -31, -45, -43, 4, -60,
|
||||
-48, -12, -34, 2, 2, 3, 13, 15,
|
||||
11, 16, 5, 46, -9, -55, -16, -57,
|
||||
29, 14, 38, -50, -2, -44, -11, -8,
|
||||
52, -27, -38, -7, 20, 47, 17, -59,
|
||||
0, 47, 46, -63, 35, -17, 19, 33,
|
||||
68, -19, 2, 15, -16, 28, -16, -103,
|
||||
26, -35, 47, -39, -60, 30, 31, -23,
|
||||
-52, -13, 116, 47, -25, 30, 40, 30,
|
||||
-22, 2, 12, -27, -18, 31, -10, 27,
|
||||
-8, -66, 12, 14, 4, -26, -28, -13,
|
||||
3, 13, -26, -51, 37, 5, 2, -21,
|
||||
47, 3, 13, 25, -41, -27, -8, -4,
|
||||
5, -76, -33, 28, 10, 9, -46, -74,
|
||||
19, 28, 25, 31, 54, -55, 68, 38,
|
||||
-24, -32, 2, 4, 68, 11, -1, 99,
|
||||
5, 16, -2, -74, 40, 26, -26, 33,
|
||||
31, -1, -68, 14, -6, 25, 9, 29,
|
||||
60, 61, 7, -7, 0, -24, 7, 77,
|
||||
4, -1, 16, -7, 13, -15, -19, 28,
|
||||
-31, -24, -16, 37, 24, 13, 30, 10,
|
||||
-30, 11, 11, -10, 22, 60, 28, 45,
|
||||
-3, -40, -62, -5, -102, 9, -32, -27,
|
||||
-54, 21, 15, -5, 37, -43, -11, 37,
|
||||
-19, 47, -64, -128, -27, -114, 21, -66,
|
||||
59, 46, -3, -12, -87, -9, 4, 19,
|
||||
-113, -36, 78, 57, -26, -38, -77, -10,
|
||||
6, 6, -75, 25, -97, -11, 33, -46,
|
||||
1, 13, -21, -33, -20, 16, -6, -3,
|
||||
-11, -4, -27, 38, 8, -41, -2, -33,
|
||||
18, 19, -26, 1, -29, -22, -4, -14,
|
||||
-55, -11, -80, -3, 11, 34, 90, 51,
|
||||
11, 17, 43, 36, 127, -32, 29, 103,
|
||||
9, 27, 13, 64, 56, 70, -14, 3,
|
||||
-12, 10, 37, 3, 12, -22, -10, 46,
|
||||
28, 10, 20, 26, -24, 18, 9, 7,
|
||||
14, 34, -5, -7, 31, -14, -56, 11,
|
||||
-18, -8, -17, -7, -10, -40, 10, -33,
|
||||
-32, -43, 5, 9, 11, -4, 10, 50,
|
||||
-12, -5, 46, 9, 7, 1, 11, 15,
|
||||
91, -17, 7, -50, 23, 6, -30, -99,
|
||||
0, -17, 14, 8, -10, -25, -30, -69,
|
||||
-62, 31, 127, 114, -23, 101, -5, -54,
|
||||
-6, -22, 7, -56, 39, 18, -29, 0,
|
||||
46, 8, -79, 4, -21, 18, -32, 62,
|
||||
-12, -8, -12, -58, 31, -32, 17, 6,
|
||||
-24, 25, 24, 9, -4, -19, 45, 6,
|
||||
17, -14, 5, -27, 16, -4, -41, 25,
|
||||
-36, 5, 15, 12, 50, 27, 25, 23,
|
||||
-44, -69, -9, -19, -48, -8, 4, 12,
|
||||
-6, 13, -19, -30, -36, 26, 37, -1,
|
||||
-3, -30, -42, -14, -10, -20, 26, -54,
|
||||
-27, -44, 4, 73, -26, 90, 32, -69,
|
||||
-29, -16, 3, 103, 15, -17, 37, 24,
|
||||
-23, -31, 33, -37, -64, 25, 13, -81,
|
||||
-28, -32, 27, 5, -35, -23, 15, -22,
|
||||
19, -7, 9, 30, 19, -23, 27, -13,
|
||||
43, 29, -29, -6, 9, -40, -33, -33,
|
||||
-32, 9, 11, -48, -8, -23, -52, 46,
|
||||
17, -22, -42, 35, -15, -41, 16, 34,
|
||||
31, -42, -19, -11, 55, 7, -39, 89,
|
||||
-11, -33, 20, -14, 22, 32, 3, -17,
|
||||
-6, 14, 34, 1, 55, -21, -90, -8,
|
||||
18, 27, 13, -29, 21, 15, -33, -51,
|
||||
-9, -11, 4, -16, -18, 23, -4, -4,
|
||||
48, 1, 7, 29, -14, -12, -16, 17,
|
||||
35, 8, 0, -7, -2, 9, 8, 17,
|
||||
-6, 53, -32, -21, -50, 5, 99, -60,
|
||||
-5, -53, 10, -31, 12, -5, 7, 80,
|
||||
36, 18, -31, 9, 98, 36, -63, -35,
|
||||
4, -13, -28, -24, 28, -13, 18, 16,
|
||||
-1, -18, -34, 10, 20, 7, 4, 29,
|
||||
11, 25, -7, 36, 14, 45, 24, 1,
|
||||
-16, 30, 6, 35, -6, -11, -24, 13,
|
||||
-1, 27, 39, 20, 48, -11, -4, -13,
|
||||
28, 11, -31, -18, 31, -29, 22, -2,
|
||||
-20, -16, 5, 30, -12, -28, -3, 93,
|
||||
-16, 23, 18, -29, 6, -54, -37, 28,
|
||||
-3, -3, -47, -3, -36, -55, -3, 41,
|
||||
-10, 47, -2, 23, 42, -7, -71, -27,
|
||||
83, -64, 7, -24, 8, 26, -17, 15,
|
||||
12, 31, -30, -38, -13, -33, -56, 4,
|
||||
-17, 20, 18, 1, -30, -5, -6, -31,
|
||||
-14, -37, 0, 22, 10, -30, 37, -17,
|
||||
18, 6, 5, 23, -36, -32, 14, 18,
|
||||
-13, -61, -52, -69, 44, -30, 16, 18,
|
||||
-4, -25, 14, 81, 26, -8, -23, -59,
|
||||
52, -104, 17, 119, -32, 26, 17, 1,
|
||||
23, 45, 29, -64, -57, -14, 73, 21,
|
||||
-13, -13, 9, -68, -7, -52, 3, 24,
|
||||
-39, 44, -15, 27, 14, 19, -9, -28,
|
||||
-11, 5, 3, -34, -2, 2, 22, -6,
|
||||
-23, 4, 3, 13, -22, -13, -10, -18,
|
||||
29, 6, 44, -13, -24, -8, 2, 30,
|
||||
14, 43, 6, 17, -73, -6, -7, 20,
|
||||
-80, -7, -7, -28, 15, -69, -38, -5,
|
||||
-100, -35, 15, -79, 23, 29, -18, -27,
|
||||
21, -66, -37, 8, -22, -39, 48, 4,
|
||||
-13, 1, -9, 11, -29, 22, 6, -49,
|
||||
32, -14, 47, -18, -4, 44, -52, -74,
|
||||
43, 30, 23, -14, 5, 0, -27, 4,
|
||||
-7, 10, -4, 10, 1, -16, 11, -18,
|
||||
-2, -5, 2, -11, 0, -20, -4, 38,
|
||||
74, 59, 39, 64, -10, 26, -3, -40,
|
||||
-68, 3, -30, -51, 8, -19, -27, -46,
|
||||
51, 52, 54, 36, 90, 92, 14, 13,
|
||||
-5, 0, 16, -62, 16, 11, -47, -37,
|
||||
-6, -5, 21, 54, -57, 32, 42, -6,
|
||||
62, -9, 16, 21, 24, 9, -10, -4,
|
||||
33, 50, 13, -15, 1, -35, -48, 18,
|
||||
-11, -17, -67, -13, 21, 38, -44, 36,
|
||||
-16, 29, 17, 5, -10, 18, 17, -32,
|
||||
2, 8, 22, -56, -15, -32, 40, 43,
|
||||
19, 46, -7, -100, -96, 19, 53, 24,
|
||||
21, -26, -48, -101, -82, 61, 38, -85,
|
||||
-28, -34, -1, 63, -5, -5, 39, 39,
|
||||
-38, 32, -12, -28, 20, 40, -8, 2,
|
||||
31, 12, -35, -13, 20, -25, 30, 8,
|
||||
3, -13, -9, -20, 2, -13, 24, 37,
|
||||
-10, 33, 6, 20, -16, -24, -6, -6,
|
||||
-19, -5, 22, 21, 10, 11, -4, -39,
|
||||
-1, 6, 49, 41, -15, -57, 21, -62,
|
||||
77, -69, -13, 0, -74, 1, -7, -38,
|
||||
-8, 6, 63, 28, 4, 26, -52, 82,
|
||||
63, 13, 45, -33, 44, -52, -65, -21,
|
||||
-46, -49, 64, -17, 32, 24, 68, -39,
|
||||
-16, -5, -26, 28, 5, -61, -28, 2,
|
||||
24, 11, -12, -33, 9, -37, -3, -28,
|
||||
22, -37, -12, 19, 0, -18, -2, 14,
|
||||
1, 4, 8, -9, -2, 43, -17, -2,
|
||||
-66, -31, 56, -40, -87, -36, -2, -4,
|
||||
-42, -45, -1, 31, -43, -15, 27, 63,
|
||||
-11, 32, -10, -33, 27, -19, 4, 15,
|
||||
-26, -34, 29, -4, -39, -65, 14, -20,
|
||||
-21, -17, -36, 13, 59, 47, -38, -33,
|
||||
13, -37, -8, -37, -7, -6, -76, -31,
|
||||
-12, -46, 7, 24, -21, -30, -14, 9,
|
||||
15, -12, -13, 47, -27, -25, -1, -39,
|
||||
0, 20, -9, 6, 7, 4, 3, 7,
|
||||
39, 50, 22, -7, 14, -20, 1, 70,
|
||||
-28, 29, -41, 10, -16, -5, -28, -2,
|
||||
-37, 32, -18, 17, 62, -11, -20, -50,
|
||||
36, 21, -62, -12, -56, 52, 50, 17,
|
||||
3, 48, 44, -41, -25, 3, 16, -3,
|
||||
0, 33, -6, 15, 27, 34, -25, 22,
|
||||
9, 17, -11, 36, 16, -2, 12, 21,
|
||||
-52, 45, -2, -10, 46, 21, -18, 67,
|
||||
-28, -13, 30, 37, 42, 16, -9, 11,
|
||||
75, 7, -64, -40, -10, 29, 57, -23,
|
||||
5, 53, -77, 3, -17, -5, 47, -55,
|
||||
-35, -36, -13, 52, -53, -71, 52, -111,
|
||||
-23, -26, -28, 29, -43, 55, -19, 43,
|
||||
-19, 54, -12, -33, -44, -39, -19, -10,
|
||||
-31, -10, 21, 38, -57, -20, 2, -25,
|
||||
8, -6, 50, 12, 15, 25, -25, 15,
|
||||
-30, -6, 9, 25, 37, 19, -4, 31,
|
||||
-22, 2, 4, 2, 36, 7, 3, -34,
|
||||
-80, 36, -10, -2, -5, 31, -36, 49,
|
||||
-70, 20, -36, 21, 24, 25, -46, -51,
|
||||
36, -58, -48, -40, -10, 55, 71, 47,
|
||||
10, -1, 1, 2, -46, -68, 16, 13,
|
||||
0, -74, -29, 73, -52, -18, -11, 7,
|
||||
-44, -82, -32, -70, -28, -1, -39, -68,
|
||||
-6, -41, 12, -22, -16, 40, -11, -25,
|
||||
51, -9, 21, 4, 4, -34, 7, -78,
|
||||
16, 6, -38, -30, -2, -44, 32, 0,
|
||||
22, 64, 5, -72, -2, -14, -10, -16,
|
||||
-8, -25, 12, 102, -58, 37, -10, -23,
|
||||
15, 49, 7, -7, 2, -20, -32, 45,
|
||||
-6, 48, 28, 30, 33, -1, 22, -6,
|
||||
30, 65, -17, 29, 74, 37, -26, -10,
|
||||
15, -24, 19, -66, 22, -10, -31, -1,
|
||||
-18, -9, 11, 37, -4, 45, 5, 41,
|
||||
17, 1, 1, 24, -58, 41, 5, -51,
|
||||
14, 8, 43, 16, -10, -1, 45, 32,
|
||||
-64, 3, -33, -25, -3, -27, -68, 12,
|
||||
23, -11, -13, -37, -40, 4, -21, -12,
|
||||
32, -23, -19, 76, 41, -23, -24, -44,
|
||||
-65, -1, -15, 1, 71, 63, 5, 20,
|
||||
-3, 21, -23, 31, -32, 18, -2, 27,
|
||||
31, 46, -5, -39, -5, -35, 18, -18,
|
||||
-40, -10, 3, 12, 2, -2, -22, 40,
|
||||
5, -6, 60, 36, 3, 29, -27, 10,
|
||||
25, -54, 5, 26, 39, 35, -24, -37,
|
||||
30, -91, 28, -4, -21, -27, -39, -6,
|
||||
5, 12, -128, 38, -16, 29, -95, -29,
|
||||
82, -2, 35, 2, 12, 8, -22, 10,
|
||||
80, -47, 2, -25, -73, -79, 16, -30,
|
||||
-32, -66, 48, 21, -45, -11, -47, 14,
|
||||
-27, -17, -7, 15, -44, -14, -44, -26,
|
||||
-32, 26, -23, 17, -7, -28, 26, -6,
|
||||
28, 6, -26, 2, 13, -14, -23, -14,
|
||||
19, 46, 16, 2, -33, -21, 28, -17,
|
||||
-42, 44, -37, 1, -39, 28, 84, -46,
|
||||
15, 10, 13, -44, 72, -26, 26, 32,
|
||||
-28, -12, -83, 2, 10, -30, -44, -10,
|
||||
-28, 53, 45, 65, 0, -25, 57, 36,
|
||||
-33, 6, 29, 44, -53, 11, 19, -2,
|
||||
-27, 35, 32, 49, 4, 23, 38, 36,
|
||||
24, 10, 51, -39, 4, -7, 26, 37,
|
||||
-35, 11, -47, -18, 28, 16, -35, 42,
|
||||
17, -21, -41, 28, 14, -12, 11, -45,
|
||||
7, -43, -15, 18, -5, 38, -40, -50,
|
||||
-30, -21, 9, -98, 13, 12, 23, 75,
|
||||
-56, -7, -3, -4, -1, -34, 12, -49,
|
||||
11, 26, -18, -28, -17, 33, 13, -14,
|
||||
40, 24, -72, -37, 10, 17, -6, 22,
|
||||
16, 16, -6, -12, -30, -14, 10, 40,
|
||||
-23, 12, 15, -3, -15, 13, -56, -4,
|
||||
-30, 1, -3, -17, 27, 50, -5, 64,
|
||||
-36, -19, 7, 29, 22, 25, 9, -16,
|
||||
-58, -69, -40, -61, -71, -14, 42, 93,
|
||||
26, 11, -6, -58, -11, 70, -52, 19,
|
||||
9, -30, -33, 11, -37, -47, -21, -22,
|
||||
-40, 10, 47, 4, -23, 17, 48, 41,
|
||||
-48, 14, 10, 15, 34, -23, -2, -47,
|
||||
23, -32, -13, -10, -26, -26, -4, 16,
|
||||
38, -14, 0, -12, -7, -7, 20, 44,
|
||||
-1, -32, -27, -16, 4, -6, -18, 14,
|
||||
5, 4, -29, 28, 7, -7, 15, -11,
|
||||
-20, -45, -36, 16, 84, 34, -59, -30,
|
||||
22, 126, 8, 68, 79, -17, 21, -68,
|
||||
37, 5, 15, 63, 49, 127, -90, 85,
|
||||
43, 7, 16, 9, 6, -45, -57, -43,
|
||||
57, 11, -23, -11, -29, 60, -26, 0,
|
||||
7, 42, -24, 10, 23, -25, 8, -7,
|
||||
-40, 19, -17, 35, 4, 27, -39, -91,
|
||||
27, -36, 34, 2, 16, -24, 25, 7,
|
||||
-21, 5, 17, 10, -22, -30, 9, -17,
|
||||
-61, -26, 33, 21, 58, -51, -14, 69,
|
||||
-38, 20, 7, 80, -4, -65, -6, -27,
|
||||
53, -12, 47, -1, -15, 1, 60, 102,
|
||||
-79, -4, 12, 9, 22, 37, -8, -4,
|
||||
37, 2, -3, -15, -16, -11, -5, 19,
|
||||
-6, -43, 20, -25, -18, 10, -27, 0,
|
||||
-28, -27, -11, 10, -18, -2, -4, -16,
|
||||
26, 14, -6, 7, -6, 1, 53, -2,
|
||||
-29, 23, 9, -30, -6, -4, -6, 56,
|
||||
70, 0, -33, -20, -17, -9, -24, 46,
|
||||
-5, -105, 47, -46, -51, 20, 20, -53,
|
||||
-81, -1, -7, 75, -5, -21, -65, 12,
|
||||
-52, 22, -50, -12, 49, 54, 76, -81,
|
||||
10, 45, -41, -59, 18, -19, 25, 14,
|
||||
-31, -53, -5, 12, 31, 84, -23, 2,
|
||||
7, 2, 10, -32, 39, -2, -12, 1,
|
||||
-9, 0, -10, -11, 9, 15, -8, -2,
|
||||
2, -1, 10, 14, -5, -40, 19, -7,
|
||||
-7, 26, -4, 2, 1, -27, 35, 32,
|
||||
21, -31, 26, 43, -9, 4, -32, 40,
|
||||
-62, -52, 36, 22, 38, 22, 36, -96,
|
||||
6, -10, -23, -49, 15, -33, -18, -3,
|
||||
0, 41, 21, -19, 21, 23, -39, -23,
|
||||
-6, 6, 47, 56, 4, 74, 0, -98,
|
||||
29, -47, -14, -36, 21, -22, 22, 16,
|
||||
13, 12, 16, -5, 13, 17, -13, -15,
|
||||
1, -34, -26, 26, 12, 32, 27, 13,
|
||||
-67, 27, 2, 8, 10, 18, 16, 20,
|
||||
-17, -17, 57, -64, 5, 14, 19, 31,
|
||||
-18, -44, -46, -16, 4, -25, 17, -126,
|
||||
-24, 39, 4, 8, 55, -25, -34, 39,
|
||||
-16, 3, 9, 71, 72, -31, -55, 6,
|
||||
10, -25, 32, -85, -21, 18, -8, 15,
|
||||
12, -27, -7, 1, -21, -2, -5, 48,
|
||||
-16, 18, 1, -22, -26, 16, 14, -31,
|
||||
27, -6, -15, -21, 4, -14, 18, -36
|
||||
};
|
||||
|
||||
static const opus_int8 layer1_recur_weights[1728] = {
|
||||
20, 67, -99, 12, 41, -25, 49, -44,
|
||||
35, 81, 110, 47, 34, -66, -14, 14,
|
||||
-60, 34, 29, -73, 10, 41, 35, 89,
|
||||
7, -35, 22, 7, 27, -20, -6, 56,
|
||||
26, 66, 6, 33, -55, 53, 1, -21,
|
||||
14, 17, 68, 55, 59, 0, 18, -9,
|
||||
5, -41, 6, -5, -114, -12, 29, 42,
|
||||
-23, 10, 81, -27, 20, -53, -30, -62,
|
||||
40, 95, 25, -4, 3, 18, -8, -15,
|
||||
-29, -82, 2, -57, -3, -61, -29, -29,
|
||||
49, 2, -55, 5, -69, -99, -49, -51,
|
||||
6, -25, 12, 89, 44, -33, 5, 41,
|
||||
1, 23, -37, -37, -28, -48, 3, 4,
|
||||
-41, -30, -57, -35, -39, -1, -13, -56,
|
||||
-5, 50, 49, 41, -4, -4, 33, -22,
|
||||
-1, 33, 34, 18, 40, -42, 12, 1,
|
||||
-6, -2, 18, 17, 39, 44, 11, 65,
|
||||
-60, -45, 10, 91, 21, 9, -62, -11,
|
||||
8, 69, 37, 24, -30, 21, 26, -27,
|
||||
1, -28, 24, 66, -8, 6, -71, 34,
|
||||
24, 44, 58, -78, -19, 57, 17, -60,
|
||||
1, 12, -3, -1, -40, 22, 11, -5,
|
||||
25, 12, 1, 72, 79, 7, -50, 23,
|
||||
18, 13, 21, -11, -20, 5, 77, -94,
|
||||
24, 15, 57, -51, 3, 36, 53, -1,
|
||||
4, 14, 30, -31, 22, 40, 32, -11,
|
||||
-34, -36, -59, 58, 25, 21, -54, -23,
|
||||
40, 46, 18, 0, 12, 54, -96, -99,
|
||||
-59, 5, 119, -38, 50, 55, 12, -16,
|
||||
67, 0, 34, 35, 39, 35, -1, 69,
|
||||
24, 27, -30, -35, -4, -70, 2, -44,
|
||||
-7, -6, 19, -9, 60, 44, -21, -10,
|
||||
37, 43, -16, -3, 30, -15, -65, 31,
|
||||
-55, 18, -98, 76, 64, 25, 24, -18,
|
||||
-7, -68, -10, 38, 27, -60, 36, 33,
|
||||
16, 30, 34, -39, -37, 31, 12, 53,
|
||||
-54, 14, -26, -49, -128, -13, -5, -22,
|
||||
-11, -85, 55, -8, -51, -11, -33, -10,
|
||||
-31, -76, -41, 23, 44, -40, -54, -127,
|
||||
-101, 19, -23, -15, 15, 27, 58, -60,
|
||||
8, 14, -33, 1, 48, -9, -11, -123,
|
||||
3, 53, 23, 4, -28, 22, 2, -29,
|
||||
-67, 36, 12, 7, 55, -21, 88, 20,
|
||||
-1, -21, -17, 3, 41, 32, -10, -14,
|
||||
-5, -57, 67, 57, 21, 23, -2, -27,
|
||||
-73, -24, 120, 21, 18, -35, 42, -7,
|
||||
3, -45, -25, 76, -34, 50, 11, -54,
|
||||
-91, 3, -113, -20, -5, 47, 15, -47,
|
||||
17, 27, -3, -26, -7, 10, 7, 74,
|
||||
-40, 64, -7, -5, -24, -49, -24, -3,
|
||||
-10, 27, -17, -8, -3, 14, -27, 33,
|
||||
13, 39, 28, -7, -38, 29, 16, 44,
|
||||
19, 55, -3, 9, -13, -57, 43, 43,
|
||||
31, 0, -93, -17, 19, -56, 4, -12,
|
||||
-25, 37, -85, -13, -118, 33, -17, 56,
|
||||
71, -80, -4, 6, -11, -18, 47, -52,
|
||||
25, 9, 48, -107, 1, 21, 20, -3,
|
||||
10, -16, -4, 24, 17, 31, -61, -18,
|
||||
-50, 24, -10, 12, 71, 26, 11, -3,
|
||||
4, 1, 0, -7, -40, 18, 38, -34,
|
||||
38, 17, 8, -34, 2, 21, 123, -32,
|
||||
-26, 43, 14, -34, -1, -9, 37, -16,
|
||||
6, -17, -62, 68, 22, 17, 11, -75,
|
||||
33, -80, 62, -9, -75, 76, 36, -41,
|
||||
-8, -40, -11, -71, 40, -39, 62, -49,
|
||||
-81, 16, -9, -52, 52, 61, 17, -103,
|
||||
-27, -10, -8, -54, -57, 21, 23, -16,
|
||||
-52, 36, 18, 10, -5, 8, 15, -29,
|
||||
5, -19, -37, 8, -53, 6, 19, -37,
|
||||
38, -17, 48, 10, 0, 81, 46, 70,
|
||||
-29, 101, 11, 44, -44, -3, 24, 11,
|
||||
3, 14, -9, 11, 14, -45, 13, 46,
|
||||
-3, -57, 68, 44, 63, 98, 25, -28,
|
||||
-23, 15, 32, -10, 53, -6, -2, -9,
|
||||
-6, 16, -107, -11, -11, -28, 59, 57,
|
||||
-22, 38, 42, 83, 27, 5, 29, -30,
|
||||
12, -21, -13, 31, 38, -21, 58, -10,
|
||||
-10, -15, -2, -5, 11, 12, -73, -28,
|
||||
-38, 22, 2, -25, 73, -52, -12, -55,
|
||||
32, -63, 21, 51, 33, 52, -26, 55,
|
||||
-26, -26, 57, -32, -4, -52, -61, 21,
|
||||
-33, -91, -51, 69, -90, -53, -38, -44,
|
||||
12, -76, -20, 77, -45, -7, 86, 43,
|
||||
-109, -33, -105, -40, -121, -10, 0, -72,
|
||||
45, -51, -75, -49, -38, -1, -62, 18,
|
||||
-1, 30, -44, -14, -10, -67, 40, -10,
|
||||
-34, 46, -64, -32, 29, -13, 33, 3,
|
||||
-32, -5, 28, -27, -25, 93, 24, 68,
|
||||
-40, 57, 23, -3, -21, -58, 17, -39,
|
||||
-17, -22, -89, 11, 18, -46, 27, 24,
|
||||
46, 127, 61, 87, 31, 127, -36, 47,
|
||||
-23, 47, 127, -24, 110, 122, 30, 100,
|
||||
0, 96, -12, 6, 50, 44, -13, 73,
|
||||
4, 55, -11, -15, 49, 42, -6, 20,
|
||||
-35, 58, 18, 38, 42, 72, 19, -21,
|
||||
11, 9, -37, 7, 29, 31, 16, -17,
|
||||
13, -50, 19, 5, -23, 51, -16, -5,
|
||||
4, -24, 76, 10, -53, -28, -7, -65,
|
||||
74, 40, -16, -29, 32, -16, -49, -35,
|
||||
-3, 59, -96, -50, -43, -43, -61, -15,
|
||||
-8, -36, -34, -33, -14, 11, -3, -39,
|
||||
4, -114, -123, -11, -49, -21, 14, -56,
|
||||
1, 43, -63, 26, 40, 18, -10, -26,
|
||||
-14, -15, -35, -35, -11, 32, -44, -67,
|
||||
2, 22, 7, 3, -9, -30, -51, -28,
|
||||
28, 6, -22, 16, 34, -25, -52, -54,
|
||||
-8, -6, 5, 8, 20, -16, -17, -44,
|
||||
27, 3, 31, -5, -48, -1, -3, 116,
|
||||
11, 71, -31, -47, 109, 50, -22, -12,
|
||||
-57, 32, 66, 8, -25, -93, -54, -10,
|
||||
19, -76, -34, 97, 48, -36, -18, -30,
|
||||
-39, -26, -12, 28, 14, 12, -12, -31,
|
||||
38, 2, 10, 4, -40, 20, 16, -61,
|
||||
2, 64, 39, 5, 15, 33, 40, -61,
|
||||
-49, 93, -10, 33, 28, -11, -27, -18,
|
||||
39, -62, -6, -6, 62, 11, -8, 38,
|
||||
-67, 12, 27, 39, -27, 123, -18, -6,
|
||||
-65, 83, -64, 20, 19, -11, 33, 24,
|
||||
17, 56, 78, 7, -15, 54, -101, -9,
|
||||
115, -96, 50, 51, 35, 34, 27, 37,
|
||||
-40, -11, 8, -36, 42, -45, 2, -23,
|
||||
0, 67, -8, -9, -13, 50, -14, -27,
|
||||
4, 0, -8, -14, 30, -9, 29, 15,
|
||||
9, -38, 37, -8, 50, -46, 54, 41,
|
||||
-11, -8, -11, -26, 39, 45, 14, -26,
|
||||
-17, -27, 69, 38, 39, 98, 66, 0,
|
||||
42, 123, -101, -19, -83, 117, -32, 56,
|
||||
10, 12, -88, 79, -53, 56, 63, 95,
|
||||
-62, 9, 36, -13, -79, -16, 37, -46,
|
||||
35, -34, 14, 17, -54, 5, 21, -7,
|
||||
7, 63, 56, 15, 27, -76, -25, 4,
|
||||
-26, -63, 28, -67, -52, 43, -47, -70,
|
||||
40, -12, 40, -66, -37, 0, 35, 37,
|
||||
-53, 4, -17, -51, 11, 21, 14, -34,
|
||||
-4, 24, -42, 29, 22, 7, 28, 12,
|
||||
37, 39, -39, -19, 65, -60, -50, -2,
|
||||
1, 82, 39, 19, -23, -43, -22, -67,
|
||||
-35, -34, 32, 102, 81, 127, 36, 67,
|
||||
-45, 1, -67, -52, -4, 35, 20, 28,
|
||||
71, 86, -35, -9, -83, -34, 12, 9,
|
||||
-23, 2, 14, 28, -23, 7, -25, 45,
|
||||
7, 17, -37, 0, -19, 31, 26, 40,
|
||||
-27, -16, 17, 5, -21, 23, 24, 96,
|
||||
-55, 52, -19, -14, -6, 1, 50, -34,
|
||||
86, -53, 38, 2, -52, -36, -13, 60,
|
||||
-85, -120, 32, 7, -12, 22, 70, -7,
|
||||
-94, 38, -76, -31, -20, 15, -28, 7,
|
||||
6, 40, 53, 88, 3, 38, 18, -8,
|
||||
-22, -23, 51, 37, -9, 13, -32, 25,
|
||||
-21, 27, 31, 20, 18, -9, -13, 1,
|
||||
21, -24, -13, 39, 15, -11, -29, -36,
|
||||
18, 15, 8, 27, 21, -94, -1, -22,
|
||||
49, 66, -1, 6, -3, -40, -18, 6,
|
||||
28, 12, 33, -59, 62, 60, -48, 90,
|
||||
-1, 108, 9, 18, -2, 27, 77, -65,
|
||||
82, -48, -38, -19, -11, 127, 50, 66,
|
||||
18, -13, -22, 60, -38, 40, -14, -26,
|
||||
-13, 38, 67, 57, 30, 33, 26, 36,
|
||||
38, -17, 27, -28, 20, 12, -64, 18,
|
||||
5, -33, -27, 13, -26, 32, 35, -5,
|
||||
-48, -14, 92, 43, -47, -14, 40, 11,
|
||||
51, 66, 22, -63, -16, -61, 4, -28,
|
||||
27, 20, -33, -30, -21, -29, -53, 31,
|
||||
-40, 24, 43, -4, -19, 21, 67, 20,
|
||||
100, -16, -93, 78, -6, -18, -52, -37,
|
||||
-9, 66, -31, -8, 26, 18, 4, 24,
|
||||
-22, 17, -2, -13, 27, 0, 8, -18,
|
||||
-25, 5, -21, -24, -7, 18, -93, 21,
|
||||
7, 2, -75, 69, 50, -5, -15, -17,
|
||||
60, -42, 55, 1, -4, 3, 10, 46,
|
||||
16, -13, 45, -7, -10, -44, -108, 49,
|
||||
2, -15, -64, -12, -72, 32, -38, -45,
|
||||
10, -54, 13, -13, -27, -36, -64, 58,
|
||||
-62, -101, 88, -86, -71, -39, -9, -128,
|
||||
32, 15, -4, 54, -16, -39, -26, -36,
|
||||
46, 48, -64, -10, 19, 30, -13, 34,
|
||||
-8, 50, 60, -22, -6, -11, -30, 5,
|
||||
50, 32, 56, 0, 25, 6, 68, 11,
|
||||
-29, 45, -9, -12, 4, 1, 18, -49,
|
||||
0, -38, -19, 90, 29, 35, 51, 8,
|
||||
-48, 96, -1, -12, -9, -32, -63, -65,
|
||||
-7, 38, 89, 28, -85, -28, -23, -25,
|
||||
-128, 56, 79, -36, 99, -6, -37, 7,
|
||||
-13, -69, -46, -29, 25, 64, -21, 17,
|
||||
1, 42, -66, 1, 80, 26, -32, 21,
|
||||
15, 15, 6, 6, -10, 15, 127, 5,
|
||||
38, 27, 87, -57, -25, 11, 72, -21,
|
||||
-5, 11, -13, -66, 78, 36, -3, 41,
|
||||
-21, 8, -33, 23, 73, 28, 57, -25,
|
||||
-5, 4, -22, -47, 15, 4, -57, -72,
|
||||
33, 1, 18, 2, 53, -71, -99, -21,
|
||||
-3, -111, 108, 71, -14, 82, 25, 61,
|
||||
-48, 5, 9, -51, -20, -25, -3, 14,
|
||||
-33, 14, -3, -34, 22, 12, -19, -38,
|
||||
-16, 2, 21, 16, 26, -31, 75, 44,
|
||||
-31, 16, 26, 66, 17, -9, -22, -22,
|
||||
22, -44, 22, 27, 2, 58, -14, 10,
|
||||
-73, -42, 55, -25, -61, 72, -1, 30,
|
||||
-58, -25, 63, 26, -48, -40, 26, -30,
|
||||
60, 8, -17, -1, -18, -20, 43, -20,
|
||||
-4, -28, 127, -106, 29, 70, 64, -27,
|
||||
39, -33, -5, -88, -40, -52, 26, 44,
|
||||
-17, 23, 2, -49, 22, -9, -8, 86,
|
||||
49, -43, -60, 1, 10, 45, 36, -53,
|
||||
-4, 33, 38, 48, -72, 1, 19, 21,
|
||||
-65, 4, -5, -62, 27, -25, 17, -6,
|
||||
6, -45, -39, -46, 4, 26, 127, -9,
|
||||
18, -33, -18, -3, 33, 2, -5, 15,
|
||||
-26, -22, -117, -63, -17, -59, 61, -74,
|
||||
7, -47, -58, -128, -67, 15, -16, -128,
|
||||
12, 2, 20, 9, -48, -40, 43, 3,
|
||||
-40, -16, -38, -6, -22, -28, -16, -59,
|
||||
-22, 6, -5, 11, -12, -66, -40, 27,
|
||||
-62, -44, -19, 38, -3, 39, -8, 40,
|
||||
-24, 13, 21, 50, -60, -22, 53, -29,
|
||||
-6, 1, 22, -59, 0, 17, -39, 115
|
||||
};
|
||||
|
||||
static const opus_int8 layer1_bias[72] = {
|
||||
-42, 20, 16, 0, 105, 60, 1, -97,
|
||||
24, 60, 18, 13, 62, 25, 127, 34,
|
||||
79, 55, 118, 127, 95, 31, -4, 87,
|
||||
21, 12, 2, -14, 18, 23, 8, 17,
|
||||
-1, -8, 5, 4, 24, 37, 21, 13,
|
||||
36, 13, 17, 18, 37, 30, 33, 1,
|
||||
8, -16, -11, -5, -31, -3, -5, 0,
|
||||
6, 3, 58, -7, -1, -16, 5, -13,
|
||||
16, 10, -2, -14, 11, -4, 3, -11
|
||||
};
|
||||
|
||||
static const opus_int8 layer2_weights[48] = {
|
||||
-113, -88, 31, -128, -126, -61, 85, -35,
|
||||
118, -128, -61, 127, -128, -17, -128, 127,
|
||||
104, -9, -128, 33, 45, 127, 5, 83,
|
||||
84, -128, -85, -128, -45, 48, -53, -128,
|
||||
46, 127, -17, 125, 117, -41, -117, -91,
|
||||
-127, -68, -1, -89, -80, 32, 106, 7
|
||||
};
|
||||
|
||||
static const opus_int8 layer2_bias[2] = {
|
||||
14, 117
|
||||
};
|
||||
|
||||
const DenseLayer layer0 = {
|
||||
layer0_bias,
|
||||
layer0_weights,
|
||||
25, 32, 0
|
||||
};
|
||||
|
||||
const GRULayer layer1 = {
|
||||
layer1_bias,
|
||||
layer1_weights,
|
||||
layer1_recur_weights,
|
||||
32, 24
|
||||
};
|
||||
|
||||
const DenseLayer layer2 = {
|
||||
layer2_bias,
|
||||
layer2_weights,
|
||||
24, 2, 1
|
||||
};
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
|
|||
/* Slightly boost "a" by 2^-22. This is just enough to ensure -ffast-math
|
||||
does not cause output values larger than +/-1, but small enough not
|
||||
to matter even for 24-bit output. */
|
||||
a += a*2.4e-7;
|
||||
a += a*2.4e-7f;
|
||||
if (x[i*C]>0)
|
||||
a = -a;
|
||||
/* Apply soft clipping */
|
||||
|
@ -252,7 +252,7 @@ int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
|
|||
/* Number of frames encoded in bits 0 to 5 */
|
||||
ch = *data++;
|
||||
count = ch&0x3F;
|
||||
if (count <= 0 || framesize*count > 5760)
|
||||
if (count <= 0 || framesize*(opus_int32)count > 5760)
|
||||
return OPUS_INVALID_PACKET;
|
||||
len--;
|
||||
/* Padding flag is bit 6 */
|
||||
|
|
|
@ -531,7 +531,7 @@ OPUS_EXPORT int opus_packet_parse(
|
|||
const unsigned char *frames[48],
|
||||
opus_int16 size[48],
|
||||
int *payload_offset
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5);
|
||||
|
||||
/** Gets the bandwidth of an Opus packet.
|
||||
* @param [in] data <tt>char*</tt>: Opus packet
|
||||
|
|
|
@ -165,8 +165,13 @@ extern "C" {
|
|||
#define OPUS_GET_EXPERT_FRAME_DURATION_REQUEST 4041
|
||||
#define OPUS_SET_PREDICTION_DISABLED_REQUEST 4042
|
||||
#define OPUS_GET_PREDICTION_DISABLED_REQUEST 4043
|
||||
|
||||
/* Don't use 4045, it's already taken by OPUS_GET_GAIN_REQUEST */
|
||||
#define OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST 4046
|
||||
#define OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST 4047
|
||||
#define OPUS_GET_IN_DTX_REQUEST 4049
|
||||
|
||||
/** Defines for the presence of extended APIs. */
|
||||
#define OPUS_HAVE_OPUS_PROJECTION_H
|
||||
|
||||
/* Macros to trigger compilation errors when the wrong types are provided to a CTL */
|
||||
#define __opus_check_int(x) (((void)((x) == (opus_int32)0)), (opus_int32)(x))
|
||||
|
@ -208,6 +213,9 @@ extern "C" {
|
|||
#define OPUS_FRAMESIZE_20_MS 5004 /**< Use 20 ms frames */
|
||||
#define OPUS_FRAMESIZE_40_MS 5005 /**< Use 40 ms frames */
|
||||
#define OPUS_FRAMESIZE_60_MS 5006 /**< Use 60 ms frames */
|
||||
#define OPUS_FRAMESIZE_80_MS 5007 /**< Use 80 ms frames */
|
||||
#define OPUS_FRAMESIZE_100_MS 5008 /**< Use 100 ms frames */
|
||||
#define OPUS_FRAMESIZE_120_MS 5009 /**< Use 120 ms frames */
|
||||
|
||||
/**@}*/
|
||||
|
||||
|
@ -566,7 +574,9 @@ extern "C" {
|
|||
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_SET_EXPERT_FRAME_DURATION(x) OPUS_SET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int(x)
|
||||
|
@ -581,7 +591,9 @@ extern "C" {
|
|||
* <dt>OPUS_FRAMESIZE_20_MS</dt><dd>Use 20 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_40_MS</dt><dd>Use 40 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_60_MS</dt><dd>Use 60 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_VARIABLE</dt><dd>Optimize the frame size dynamically.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_80_MS</dt><dd>Use 80 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_100_MS</dt><dd>Use 100 ms frames.</dd>
|
||||
* <dt>OPUS_FRAMESIZE_120_MS</dt><dd>Use 120 ms frames.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_EXPERT_FRAME_DURATION(x) OPUS_GET_EXPERT_FRAME_DURATION_REQUEST, __opus_check_int_ptr(x)
|
||||
|
@ -681,6 +693,40 @@ extern "C" {
|
|||
*/
|
||||
#define OPUS_GET_SAMPLE_RATE(x) OPUS_GET_SAMPLE_RATE_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/** If set to 1, disables the use of phase inversion for intensity stereo,
|
||||
* improving the quality of mono downmixes, but slightly reducing normal
|
||||
* stereo quality. Disabling phase inversion in the decoder does not comply
|
||||
* with RFC 6716, although it does not cause any interoperability issue and
|
||||
* is expected to become part of the Opus standard once RFC 6716 is updated
|
||||
* by draft-ietf-codec-opus-update.
|
||||
* @see OPUS_GET_PHASE_INVERSION_DISABLED
|
||||
* @param[in] x <tt>opus_int32</tt>: Allowed values:
|
||||
* <dl>
|
||||
* <dt>0</dt><dd>Enable phase inversion (default).</dd>
|
||||
* <dt>1</dt><dd>Disable phase inversion.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_SET_PHASE_INVERSION_DISABLED(x) OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int(x)
|
||||
/** Gets the encoder's configured phase inversion status.
|
||||
* @see OPUS_SET_PHASE_INVERSION_DISABLED
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||
* <dl>
|
||||
* <dt>0</dt><dd>Stereo phase inversion enabled (default).</dd>
|
||||
* <dt>1</dt><dd>Stereo phase inversion disabled.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_PHASE_INVERSION_DISABLED(x) OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST, __opus_check_int_ptr(x)
|
||||
/** Gets the DTX state of the encoder.
|
||||
* Returns whether the last encoded frame was either a comfort noise update
|
||||
* during DTX or not encoded because of DTX.
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns one of the following values:
|
||||
* <dl>
|
||||
* <dt>0</dt><dd>The encoder is not in DTX.</dd>
|
||||
* <dt>1</dt><dd>The encoder is in DTX.</dd>
|
||||
* </dl>
|
||||
* @hideinitializer */
|
||||
#define OPUS_GET_IN_DTX(x) OPUS_GET_IN_DTX_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** @defgroup opus_decoderctls Decoder related CTLs
|
||||
|
|
|
@ -273,7 +273,7 @@ OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusMSEncoder *opus_multistream_surround_enc
|
|||
unsigned char *mapping,
|
||||
int application,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(5);
|
||||
) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6);
|
||||
|
||||
/** Initialize a previously allocated multistream encoder state.
|
||||
* The memory pointed to by \a st must be at least the size returned by
|
||||
|
@ -342,7 +342,7 @@ OPUS_EXPORT int opus_multistream_surround_encoder_init(
|
|||
int *coupled_streams,
|
||||
unsigned char *mapping,
|
||||
int application
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6) OPUS_ARG_NONNULL(7);
|
||||
|
||||
/** Encodes a multistream Opus frame.
|
||||
* @param st <tt>OpusMSEncoder*</tt>: Multistream encoder state.
|
||||
|
|
|
@ -0,0 +1,568 @@
|
|||
/* Copyright (c) 2017 Google Inc.
|
||||
Written by Andrew Allen */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file opus_projection.h
|
||||
* @brief Opus projection reference API
|
||||
*/
|
||||
|
||||
#ifndef OPUS_PROJECTION_H
|
||||
#define OPUS_PROJECTION_H
|
||||
|
||||
#include "opus_multistream.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @cond OPUS_INTERNAL_DOC */
|
||||
|
||||
/** These are the actual encoder and decoder CTL ID numbers.
|
||||
* They should not be used directly by applications.c
|
||||
* In general, SETs should be even and GETs should be odd.*/
|
||||
/**@{*/
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST 6001
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST 6003
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST 6005
|
||||
/**@}*/
|
||||
|
||||
|
||||
/** @endcond */
|
||||
|
||||
/** @defgroup opus_projection_ctls Projection specific encoder and decoder CTLs
|
||||
*
|
||||
* These are convenience macros that are specific to the
|
||||
* opus_projection_encoder_ctl() and opus_projection_decoder_ctl()
|
||||
* interface.
|
||||
* The CTLs from @ref opus_genericctls, @ref opus_encoderctls,
|
||||
* @ref opus_decoderctls, and @ref opus_multistream_ctls may be applied to a
|
||||
* projection encoder or decoder as well.
|
||||
*/
|
||||
/**@{*/
|
||||
|
||||
/** Gets the gain (in dB. S7.8-format) of the demixing matrix from the encoder.
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns the gain (in dB. S7.8-format)
|
||||
* of the demixing matrix.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
|
||||
/** Gets the size in bytes of the demixing matrix from the encoder.
|
||||
* @param[out] x <tt>opus_int32 *</tt>: Returns the size in bytes of the
|
||||
* demixing matrix.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE(x) OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST, __opus_check_int_ptr(x)
|
||||
|
||||
|
||||
/** Copies the demixing matrix to the supplied pointer location.
|
||||
* @param[out] x <tt>unsigned char *</tt>: Returns the demixing matrix to the
|
||||
* supplied pointer location.
|
||||
* @param y <tt>opus_int32</tt>: The size in bytes of the reserved memory at the
|
||||
* pointer location.
|
||||
* @hideinitializer
|
||||
*/
|
||||
#define OPUS_PROJECTION_GET_DEMIXING_MATRIX(x,y) OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST, x, __opus_check_int(y)
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** Opus projection encoder state.
|
||||
* This contains the complete state of a projection Opus encoder.
|
||||
* It is position independent and can be freely copied.
|
||||
* @see opus_projection_ambisonics_encoder_create
|
||||
*/
|
||||
typedef struct OpusProjectionEncoder OpusProjectionEncoder;
|
||||
|
||||
|
||||
/** Opus projection decoder state.
|
||||
* This contains the complete state of a projection Opus decoder.
|
||||
* It is position independent and can be freely copied.
|
||||
* @see opus_projection_decoder_create
|
||||
* @see opus_projection_decoder_init
|
||||
*/
|
||||
typedef struct OpusProjectionDecoder OpusProjectionDecoder;
|
||||
|
||||
|
||||
/**\name Projection encoder functions */
|
||||
/**@{*/
|
||||
|
||||
/** Gets the size of an OpusProjectionEncoder structure.
|
||||
* @param channels <tt>int</tt>: The total number of input channels to encode.
|
||||
* This must be no more than 255.
|
||||
* @param mapping_family <tt>int</tt>: The mapping family to use for selecting
|
||||
* the appropriate projection.
|
||||
* @returns The size in bytes on success, or a negative error code
|
||||
* (see @ref opus_errorcodes) on error.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_ambisonics_encoder_get_size(
|
||||
int channels,
|
||||
int mapping_family
|
||||
);
|
||||
|
||||
|
||||
/** Allocates and initializes a projection encoder state.
|
||||
* Call opus_projection_encoder_destroy() to release
|
||||
* this object when finished.
|
||||
* @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param channels <tt>int</tt>: Number of channels in the input signal.
|
||||
* This must be at most 255.
|
||||
* It may be greater than the number of
|
||||
* coded channels (<code>streams +
|
||||
* coupled_streams</code>).
|
||||
* @param mapping_family <tt>int</tt>: The mapping family to use for selecting
|
||||
* the appropriate projection.
|
||||
* @param[out] streams <tt>int *</tt>: The total number of streams that will
|
||||
* be encoded from the input.
|
||||
* @param[out] coupled_streams <tt>int *</tt>: Number of coupled (2 channel)
|
||||
* streams that will be encoded from the input.
|
||||
* @param application <tt>int</tt>: The target encoder application.
|
||||
* This must be one of the following:
|
||||
* <dl>
|
||||
* <dt>#OPUS_APPLICATION_VOIP</dt>
|
||||
* <dd>Process signal for improved speech intelligibility.</dd>
|
||||
* <dt>#OPUS_APPLICATION_AUDIO</dt>
|
||||
* <dd>Favor faithfulness to the original input.</dd>
|
||||
* <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
|
||||
* <dd>Configure the minimum possible coding delay by disabling certain modes
|
||||
* of operation.</dd>
|
||||
* </dl>
|
||||
* @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
|
||||
* code (see @ref opus_errorcodes) on
|
||||
* failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionEncoder *opus_projection_ambisonics_encoder_create(
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int mapping_family,
|
||||
int *streams,
|
||||
int *coupled_streams,
|
||||
int application,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(4) OPUS_ARG_NONNULL(5);
|
||||
|
||||
|
||||
/** Initialize a previously allocated projection encoder state.
|
||||
* The memory pointed to by \a st must be at least the size returned by
|
||||
* opus_projection_ambisonics_encoder_get_size().
|
||||
* This is intended for applications which use their own allocator instead of
|
||||
* malloc.
|
||||
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
|
||||
* @see opus_projection_ambisonics_encoder_create
|
||||
* @see opus_projection_ambisonics_encoder_get_size
|
||||
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state to initialize.
|
||||
* @param Fs <tt>opus_int32</tt>: Sampling rate of the input signal (in Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param channels <tt>int</tt>: Number of channels in the input signal.
|
||||
* This must be at most 255.
|
||||
* It may be greater than the number of
|
||||
* coded channels (<code>streams +
|
||||
* coupled_streams</code>).
|
||||
* @param streams <tt>int</tt>: The total number of streams to encode from the
|
||||
* input.
|
||||
* This must be no more than the number of channels.
|
||||
* @param coupled_streams <tt>int</tt>: Number of coupled (2 channel) streams
|
||||
* to encode.
|
||||
* This must be no larger than the total
|
||||
* number of streams.
|
||||
* Additionally, The total number of
|
||||
* encoded channels (<code>streams +
|
||||
* coupled_streams</code>) must be no
|
||||
* more than the number of input channels.
|
||||
* @param application <tt>int</tt>: The target encoder application.
|
||||
* This must be one of the following:
|
||||
* <dl>
|
||||
* <dt>#OPUS_APPLICATION_VOIP</dt>
|
||||
* <dd>Process signal for improved speech intelligibility.</dd>
|
||||
* <dt>#OPUS_APPLICATION_AUDIO</dt>
|
||||
* <dd>Favor faithfulness to the original input.</dd>
|
||||
* <dt>#OPUS_APPLICATION_RESTRICTED_LOWDELAY</dt>
|
||||
* <dd>Configure the minimum possible coding delay by disabling certain modes
|
||||
* of operation.</dd>
|
||||
* </dl>
|
||||
* @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
|
||||
* on failure.
|
||||
*/
|
||||
OPUS_EXPORT int opus_projection_ambisonics_encoder_init(
|
||||
OpusProjectionEncoder *st,
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int mapping_family,
|
||||
int *streams,
|
||||
int *coupled_streams,
|
||||
int application
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(5) OPUS_ARG_NONNULL(6);
|
||||
|
||||
|
||||
/** Encodes a projection Opus frame.
|
||||
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
|
||||
* @param[in] pcm <tt>const opus_int16*</tt>: The input signal as interleaved
|
||||
* samples.
|
||||
* This must contain
|
||||
* <code>frame_size*channels</code>
|
||||
* samples.
|
||||
* @param frame_size <tt>int</tt>: Number of samples per channel in the input
|
||||
* signal.
|
||||
* This must be an Opus frame size for the
|
||||
* encoder's sampling rate.
|
||||
* For example, at 48 kHz the permitted values
|
||||
* are 120, 240, 480, 960, 1920, and 2880.
|
||||
* Passing in a duration of less than 10 ms
|
||||
* (480 samples at 48 kHz) will prevent the
|
||||
* encoder from using the LPC or hybrid modes.
|
||||
* @param[out] data <tt>unsigned char*</tt>: Output payload.
|
||||
* This must contain storage for at
|
||||
* least \a max_data_bytes.
|
||||
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
|
||||
* memory for the output
|
||||
* payload. This may be
|
||||
* used to impose an upper limit on
|
||||
* the instant bitrate, but should
|
||||
* not be used as the only bitrate
|
||||
* control. Use #OPUS_SET_BITRATE to
|
||||
* control the bitrate.
|
||||
* @returns The length of the encoded packet (in bytes) on success or a
|
||||
* negative error code (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode(
|
||||
OpusProjectionEncoder *st,
|
||||
const opus_int16 *pcm,
|
||||
int frame_size,
|
||||
unsigned char *data,
|
||||
opus_int32 max_data_bytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
|
||||
/** Encodes a projection Opus frame from floating point input.
|
||||
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
|
||||
* @param[in] pcm <tt>const float*</tt>: The input signal as interleaved
|
||||
* samples with a normal range of
|
||||
* +/-1.0.
|
||||
* Samples with a range beyond +/-1.0
|
||||
* are supported but will be clipped by
|
||||
* decoders using the integer API and
|
||||
* should only be used if it is known
|
||||
* that the far end supports extended
|
||||
* dynamic range.
|
||||
* This must contain
|
||||
* <code>frame_size*channels</code>
|
||||
* samples.
|
||||
* @param frame_size <tt>int</tt>: Number of samples per channel in the input
|
||||
* signal.
|
||||
* This must be an Opus frame size for the
|
||||
* encoder's sampling rate.
|
||||
* For example, at 48 kHz the permitted values
|
||||
* are 120, 240, 480, 960, 1920, and 2880.
|
||||
* Passing in a duration of less than 10 ms
|
||||
* (480 samples at 48 kHz) will prevent the
|
||||
* encoder from using the LPC or hybrid modes.
|
||||
* @param[out] data <tt>unsigned char*</tt>: Output payload.
|
||||
* This must contain storage for at
|
||||
* least \a max_data_bytes.
|
||||
* @param [in] max_data_bytes <tt>opus_int32</tt>: Size of the allocated
|
||||
* memory for the output
|
||||
* payload. This may be
|
||||
* used to impose an upper limit on
|
||||
* the instant bitrate, but should
|
||||
* not be used as the only bitrate
|
||||
* control. Use #OPUS_SET_BITRATE to
|
||||
* control the bitrate.
|
||||
* @returns The length of the encoded packet (in bytes) on success or a
|
||||
* negative error code (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_encode_float(
|
||||
OpusProjectionEncoder *st,
|
||||
const float *pcm,
|
||||
int frame_size,
|
||||
unsigned char *data,
|
||||
opus_int32 max_data_bytes
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(2) OPUS_ARG_NONNULL(4);
|
||||
|
||||
|
||||
/** Frees an <code>OpusProjectionEncoder</code> allocated by
|
||||
* opus_projection_ambisonics_encoder_create().
|
||||
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state to be freed.
|
||||
*/
|
||||
OPUS_EXPORT void opus_projection_encoder_destroy(OpusProjectionEncoder *st);
|
||||
|
||||
|
||||
/** Perform a CTL function on a projection Opus encoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated by a
|
||||
* convenience macro.
|
||||
* @param st <tt>OpusProjectionEncoder*</tt>: Projection encoder state.
|
||||
* @param request This and all remaining parameters should be replaced by one
|
||||
* of the convenience macros in @ref opus_genericctls,
|
||||
* @ref opus_encoderctls, @ref opus_multistream_ctls, or
|
||||
* @ref opus_projection_ctls
|
||||
* @see opus_genericctls
|
||||
* @see opus_encoderctls
|
||||
* @see opus_multistream_ctls
|
||||
* @see opus_projection_ctls
|
||||
*/
|
||||
OPUS_EXPORT int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**\name Projection decoder functions */
|
||||
/**@{*/
|
||||
|
||||
/** Gets the size of an <code>OpusProjectionDecoder</code> structure.
|
||||
* @param channels <tt>int</tt>: The total number of output channels.
|
||||
* This must be no more than 255.
|
||||
* @param streams <tt>int</tt>: The total number of streams coded in the
|
||||
* input.
|
||||
* This must be no more than 255.
|
||||
* @param coupled_streams <tt>int</tt>: Number streams to decode as coupled
|
||||
* (2 channel) streams.
|
||||
* This must be no larger than the total
|
||||
* number of streams.
|
||||
* Additionally, The total number of
|
||||
* coded channels (<code>streams +
|
||||
* coupled_streams</code>) must be no
|
||||
* more than 255.
|
||||
* @returns The size in bytes on success, or a negative error code
|
||||
* (see @ref opus_errorcodes) on error.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT opus_int32 opus_projection_decoder_get_size(
|
||||
int channels,
|
||||
int streams,
|
||||
int coupled_streams
|
||||
);
|
||||
|
||||
|
||||
/** Allocates and initializes a projection decoder state.
|
||||
* Call opus_projection_decoder_destroy() to release
|
||||
* this object when finished.
|
||||
* @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param channels <tt>int</tt>: Number of channels to output.
|
||||
* This must be at most 255.
|
||||
* It may be different from the number of coded
|
||||
* channels (<code>streams +
|
||||
* coupled_streams</code>).
|
||||
* @param streams <tt>int</tt>: The total number of streams coded in the
|
||||
* input.
|
||||
* This must be no more than 255.
|
||||
* @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
|
||||
* (2 channel) streams.
|
||||
* This must be no larger than the total
|
||||
* number of streams.
|
||||
* Additionally, The total number of
|
||||
* coded channels (<code>streams +
|
||||
* coupled_streams</code>) must be no
|
||||
* more than 255.
|
||||
* @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: Demixing matrix
|
||||
* that mapping from coded channels to output channels,
|
||||
* as described in @ref opus_projection and
|
||||
* @ref opus_projection_ctls.
|
||||
* @param demixing_matrix_size <tt>opus_int32</tt>: The size in bytes of the
|
||||
* demixing matrix, as
|
||||
* described in @ref
|
||||
* opus_projection_ctls.
|
||||
* @param[out] error <tt>int *</tt>: Returns #OPUS_OK on success, or an error
|
||||
* code (see @ref opus_errorcodes) on
|
||||
* failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT OpusProjectionDecoder *opus_projection_decoder_create(
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int streams,
|
||||
int coupled_streams,
|
||||
unsigned char *demixing_matrix,
|
||||
opus_int32 demixing_matrix_size,
|
||||
int *error
|
||||
) OPUS_ARG_NONNULL(5);
|
||||
|
||||
|
||||
/** Intialize a previously allocated projection decoder state object.
|
||||
* The memory pointed to by \a st must be at least the size returned by
|
||||
* opus_projection_decoder_get_size().
|
||||
* This is intended for applications which use their own allocator instead of
|
||||
* malloc.
|
||||
* To reset a previously initialized state, use the #OPUS_RESET_STATE CTL.
|
||||
* @see opus_projection_decoder_create
|
||||
* @see opus_projection_deocder_get_size
|
||||
* @param st <tt>OpusProjectionDecoder*</tt>: Projection encoder state to initialize.
|
||||
* @param Fs <tt>opus_int32</tt>: Sampling rate to decode at (in Hz).
|
||||
* This must be one of 8000, 12000, 16000,
|
||||
* 24000, or 48000.
|
||||
* @param channels <tt>int</tt>: Number of channels to output.
|
||||
* This must be at most 255.
|
||||
* It may be different from the number of coded
|
||||
* channels (<code>streams +
|
||||
* coupled_streams</code>).
|
||||
* @param streams <tt>int</tt>: The total number of streams coded in the
|
||||
* input.
|
||||
* This must be no more than 255.
|
||||
* @param coupled_streams <tt>int</tt>: Number of streams to decode as coupled
|
||||
* (2 channel) streams.
|
||||
* This must be no larger than the total
|
||||
* number of streams.
|
||||
* Additionally, The total number of
|
||||
* coded channels (<code>streams +
|
||||
* coupled_streams</code>) must be no
|
||||
* more than 255.
|
||||
* @param[in] demixing_matrix <tt>const unsigned char[demixing_matrix_size]</tt>: Demixing matrix
|
||||
* that mapping from coded channels to output channels,
|
||||
* as described in @ref opus_projection and
|
||||
* @ref opus_projection_ctls.
|
||||
* @param demixing_matrix_size <tt>opus_int32</tt>: The size in bytes of the
|
||||
* demixing matrix, as
|
||||
* described in @ref
|
||||
* opus_projection_ctls.
|
||||
* @returns #OPUS_OK on success, or an error code (see @ref opus_errorcodes)
|
||||
* on failure.
|
||||
*/
|
||||
OPUS_EXPORT int opus_projection_decoder_init(
|
||||
OpusProjectionDecoder *st,
|
||||
opus_int32 Fs,
|
||||
int channels,
|
||||
int streams,
|
||||
int coupled_streams,
|
||||
unsigned char *demixing_matrix,
|
||||
opus_int32 demixing_matrix_size
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(6);
|
||||
|
||||
|
||||
/** Decode a projection Opus packet.
|
||||
* @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
|
||||
* @param[in] data <tt>const unsigned char*</tt>: Input payload.
|
||||
* Use a <code>NULL</code>
|
||||
* pointer to indicate packet
|
||||
* loss.
|
||||
* @param len <tt>opus_int32</tt>: Number of bytes in payload.
|
||||
* @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
|
||||
* samples.
|
||||
* This must contain room for
|
||||
* <code>frame_size*channels</code>
|
||||
* samples.
|
||||
* @param frame_size <tt>int</tt>: The number of samples per channel of
|
||||
* available space in \a pcm.
|
||||
* If this is less than the maximum packet duration
|
||||
* (120 ms; 5760 for 48kHz), this function will not be capable
|
||||
* of decoding some packets. In the case of PLC (data==NULL)
|
||||
* or FEC (decode_fec=1), then frame_size needs to be exactly
|
||||
* the duration of audio that is missing, otherwise the
|
||||
* decoder will not be in the optimal state to decode the
|
||||
* next incoming packet. For the PLC and FEC cases, frame_size
|
||||
* <b>must</b> be a multiple of 2.5 ms.
|
||||
* @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
|
||||
* forward error correction data be decoded.
|
||||
* If no such data is available, the frame is
|
||||
* decoded as if it were lost.
|
||||
* @returns Number of samples decoded on success or a negative error code
|
||||
* (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode(
|
||||
OpusProjectionDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
opus_int16 *pcm,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
|
||||
/** Decode a projection Opus packet with floating point output.
|
||||
* @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
|
||||
* @param[in] data <tt>const unsigned char*</tt>: Input payload.
|
||||
* Use a <code>NULL</code>
|
||||
* pointer to indicate packet
|
||||
* loss.
|
||||
* @param len <tt>opus_int32</tt>: Number of bytes in payload.
|
||||
* @param[out] pcm <tt>opus_int16*</tt>: Output signal, with interleaved
|
||||
* samples.
|
||||
* This must contain room for
|
||||
* <code>frame_size*channels</code>
|
||||
* samples.
|
||||
* @param frame_size <tt>int</tt>: The number of samples per channel of
|
||||
* available space in \a pcm.
|
||||
* If this is less than the maximum packet duration
|
||||
* (120 ms; 5760 for 48kHz), this function will not be capable
|
||||
* of decoding some packets. In the case of PLC (data==NULL)
|
||||
* or FEC (decode_fec=1), then frame_size needs to be exactly
|
||||
* the duration of audio that is missing, otherwise the
|
||||
* decoder will not be in the optimal state to decode the
|
||||
* next incoming packet. For the PLC and FEC cases, frame_size
|
||||
* <b>must</b> be a multiple of 2.5 ms.
|
||||
* @param decode_fec <tt>int</tt>: Flag (0 or 1) to request that any in-band
|
||||
* forward error correction data be decoded.
|
||||
* If no such data is available, the frame is
|
||||
* decoded as if it were lost.
|
||||
* @returns Number of samples decoded on success or a negative error code
|
||||
* (see @ref opus_errorcodes) on failure.
|
||||
*/
|
||||
OPUS_EXPORT OPUS_WARN_UNUSED_RESULT int opus_projection_decode_float(
|
||||
OpusProjectionDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
float *pcm,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
) OPUS_ARG_NONNULL(1) OPUS_ARG_NONNULL(4);
|
||||
|
||||
|
||||
/** Perform a CTL function on a projection Opus decoder.
|
||||
*
|
||||
* Generally the request and subsequent arguments are generated by a
|
||||
* convenience macro.
|
||||
* @param st <tt>OpusProjectionDecoder*</tt>: Projection decoder state.
|
||||
* @param request This and all remaining parameters should be replaced by one
|
||||
* of the convenience macros in @ref opus_genericctls,
|
||||
* @ref opus_decoderctls, @ref opus_multistream_ctls, or
|
||||
* @ref opus_projection_ctls.
|
||||
* @see opus_genericctls
|
||||
* @see opus_decoderctls
|
||||
* @see opus_multistream_ctls
|
||||
* @see opus_projection_ctls
|
||||
*/
|
||||
OPUS_EXPORT int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...) OPUS_ARG_NONNULL(1);
|
||||
|
||||
|
||||
/** Frees an <code>OpusProjectionDecoder</code> allocated by
|
||||
* opus_projection_decoder_create().
|
||||
* @param st <tt>OpusProjectionDecoder</tt>: Projection decoder state to be freed.
|
||||
*/
|
||||
OPUS_EXPORT void opus_projection_decoder_destroy(OpusProjectionDecoder *st);
|
||||
|
||||
|
||||
/**@}*/
|
||||
|
||||
/**@}*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPUS_PROJECTION_H */
|
|
@ -33,14 +33,29 @@
|
|||
#ifndef OPUS_TYPES_H
|
||||
#define OPUS_TYPES_H
|
||||
|
||||
/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
|
||||
#if (defined(__STDC__) && __STDC__ && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
|
||||
#include <stdint.h>
|
||||
#define opus_int int /* used for counters etc; at least 16 bits */
|
||||
#define opus_int64 long long
|
||||
#define opus_int8 signed char
|
||||
|
||||
#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
|
||||
#define opus_uint64 unsigned long long
|
||||
#define opus_uint8 unsigned char
|
||||
|
||||
/* Use the real stdint.h if it's there (taken from Paul Hsieh's pstdint.h) */
|
||||
#if (defined(__STDC__) && __STDC__ && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || (defined(__GNUC__) && (defined(_STDINT_H) || defined(_STDINT_H_)) || defined (HAVE_STDINT_H))
|
||||
#include <stdint.h>
|
||||
# undef opus_int64
|
||||
# undef opus_int8
|
||||
# undef opus_uint64
|
||||
# undef opus_uint8
|
||||
typedef int8_t opus_int8;
|
||||
typedef uint8_t opus_uint8;
|
||||
typedef int16_t opus_int16;
|
||||
typedef uint16_t opus_uint16;
|
||||
typedef int32_t opus_int32;
|
||||
typedef uint32_t opus_uint32;
|
||||
typedef int64_t opus_int64;
|
||||
typedef uint64_t opus_uint64;
|
||||
#elif defined(_WIN32)
|
||||
|
||||
# if defined(__CYGWIN__)
|
||||
|
@ -148,12 +163,4 @@
|
|||
|
||||
#endif
|
||||
|
||||
#define opus_int int /* used for counters etc; at least 16 bits */
|
||||
#define opus_int64 long long
|
||||
#define opus_int8 signed char
|
||||
|
||||
#define opus_uint unsigned int /* used for counters etc; at least 16 bits */
|
||||
#define opus_uint64 unsigned long long
|
||||
#define opus_uint8 unsigned char
|
||||
|
||||
#endif /* OPUS_TYPES_H */
|
||||
|
|
|
@ -239,7 +239,8 @@ struct OpusHead{
|
|||
-32768...32767.
|
||||
The <tt>libopusfile</tt> API will automatically apply this gain to the
|
||||
decoded output before returning it, scaling it by
|
||||
<code>pow(10,output_gain/(20.0*256))</code>.*/
|
||||
<code>pow(10,output_gain/(20.0*256))</code>.
|
||||
You can adjust this behavior with op_set_gain_offset().*/
|
||||
int output_gain;
|
||||
/**The channel mapping family, in the range 0...255.
|
||||
Channel mapping family 0 covers mono or stereo in a single stream.
|
||||
|
@ -1154,16 +1155,18 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
|
|||
int *_error,...) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Open a stream using the given set of callbacks to access it.
|
||||
\param _source The stream to read from (e.g., a <code>FILE *</code>).
|
||||
\param _stream The stream to read from (e.g., a <code>FILE *</code>).
|
||||
This value will be passed verbatim as the first
|
||||
argument to all of the callbacks.
|
||||
\param _cb The callbacks with which to access the stream.
|
||||
<code><a href="#op_read_func">read()</a></code> must
|
||||
be implemented.
|
||||
<code><a href="#op_seek_func">seek()</a></code> and
|
||||
<code><a href="#op_tell_func">tell()</a></code> may
|
||||
be <code>NULL</code>, or may always return -1 to
|
||||
indicate a source is unseekable, but if
|
||||
indicate a stream is unseekable, but if
|
||||
<code><a href="#op_seek_func">seek()</a></code> is
|
||||
implemented and succeeds on a particular source, then
|
||||
implemented and succeeds on a particular stream, then
|
||||
<code><a href="#op_tell_func">tell()</a></code> must
|
||||
also.
|
||||
<code><a href="#op_close_func">close()</a></code> may
|
||||
|
@ -1226,11 +1229,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_open_url(const char *_url,
|
|||
basic validity checks.</dd>
|
||||
</dl>
|
||||
\return A freshly opened \c OggOpusFile, or <code>NULL</code> on error.
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the source
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the stream
|
||||
if the call fails.
|
||||
The calling application is responsible for closing the source if
|
||||
The calling application is responsible for closing the stream if
|
||||
this call returns an error.*/
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_source,
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_open_callbacks(void *_stream,
|
||||
const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
|
||||
size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
|
||||
|
||||
|
@ -1332,18 +1335,20 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
|
|||
For new code, you are likely better off using op_test() instead, which
|
||||
is less resource-intensive, requires less data to succeed, and imposes a
|
||||
hard limit on the amount of data it examines (important for unseekable
|
||||
sources, where all such data must be buffered until you are sure of the
|
||||
streams, where all such data must be buffered until you are sure of the
|
||||
stream type).
|
||||
\param _source The stream to read from (e.g., a <code>FILE *</code>).
|
||||
\param _stream The stream to read from (e.g., a <code>FILE *</code>).
|
||||
This value will be passed verbatim as the first
|
||||
argument to all of the callbacks.
|
||||
\param _cb The callbacks with which to access the stream.
|
||||
<code><a href="#op_read_func">read()</a></code> must
|
||||
be implemented.
|
||||
<code><a href="#op_seek_func">seek()</a></code> and
|
||||
<code><a href="#op_tell_func">tell()</a></code> may
|
||||
be <code>NULL</code>, or may always return -1 to
|
||||
indicate a source is unseekable, but if
|
||||
indicate a stream is unseekable, but if
|
||||
<code><a href="#op_seek_func">seek()</a></code> is
|
||||
implemented and succeeds on a particular source, then
|
||||
implemented and succeeds on a particular stream, then
|
||||
<code><a href="#op_tell_func">tell()</a></code> must
|
||||
also.
|
||||
<code><a href="#op_close_func">close()</a></code> may
|
||||
|
@ -1373,11 +1378,11 @@ OP_WARN_UNUSED_RESULT OggOpusFile *op_test_url(const char *_url,
|
|||
See op_open_callbacks() for a full list of failure
|
||||
codes.
|
||||
\return A partially opened \c OggOpusFile, or <code>NULL</code> on error.
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the source
|
||||
<tt>libopusfile</tt> does <em>not</em> take ownership of the stream
|
||||
if the call fails.
|
||||
The calling application is responsible for closing the source if
|
||||
The calling application is responsible for closing the stream if
|
||||
this call returns an error.*/
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_source,
|
||||
OP_WARN_UNUSED_RESULT OggOpusFile *op_test_callbacks(void *_stream,
|
||||
const OpusFileCallbacks *_cb,const unsigned char *_initial_data,
|
||||
size_t _initial_bytes,int *_error) OP_ARG_NONNULL(2);
|
||||
|
||||
|
@ -1434,7 +1439,7 @@ void op_free(OggOpusFile *_of);
|
|||
Their documention will indicate so explicitly.*/
|
||||
/*@{*/
|
||||
|
||||
/**Returns whether or not the data source being read is seekable.
|
||||
/**Returns whether or not the stream being read is seekable.
|
||||
This is true if
|
||||
<ol>
|
||||
<li>The <code><a href="#op_seek_func">seek()</a></code> and
|
||||
|
@ -1455,9 +1460,9 @@ int op_seekable(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
return 1.
|
||||
The actual number of links is not known until the stream is fully opened.
|
||||
\param _of The \c OggOpusFile from which to retrieve the link count.
|
||||
\return For fully-open seekable sources, this returns the total number of
|
||||
\return For fully-open seekable streams, this returns the total number of
|
||||
links in the whole stream, which will be at least 1.
|
||||
For partially-open or unseekable sources, this always returns 1.*/
|
||||
For partially-open or unseekable streams, this always returns 1.*/
|
||||
int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
||||
|
||||
/**Get the serial number of the given link in a (possibly-chained) Ogg Opus
|
||||
|
@ -1471,7 +1476,7 @@ int op_link_count(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
\return The serial number of the given link.
|
||||
If \a _li is greater than the total number of links, this returns
|
||||
the serial number of the last link.
|
||||
If the source is not seekable, this always returns the serial number
|
||||
If the stream is not seekable, this always returns the serial number
|
||||
of the current link.*/
|
||||
opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
|
@ -1488,7 +1493,7 @@ opus_uint32 op_serialno(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\return The channel count of the given link.
|
||||
If \a _li is greater than the total number of links, this returns
|
||||
the channel count of the last link.
|
||||
If the source is not seekable, this always returns the channel count
|
||||
If the stream is not seekable, this always returns the channel count
|
||||
of the current link.*/
|
||||
int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
||||
|
@ -1507,9 +1512,9 @@ int op_channel_count(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
compressed size of link \a _li if it is non-negative, or a negative
|
||||
value on error.
|
||||
The compressed size of the entire stream may be smaller than that
|
||||
of the underlying source if trailing garbage was detected in the
|
||||
of the underlying stream if trailing garbage was detected in the
|
||||
file.
|
||||
\retval #OP_EINVAL The source is not seekable (so we can't know the length),
|
||||
\retval #OP_EINVAL The stream is not seekable (so we can't know the length),
|
||||
\a _li wasn't less than the total number of links in
|
||||
the stream, or the stream was only partially open.*/
|
||||
opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
@ -1527,7 +1532,7 @@ opus_int64 op_raw_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\return The PCM length of the entire stream if \a _li is negative, the PCM
|
||||
length of link \a _li if it is non-negative, or a negative value on
|
||||
error.
|
||||
\retval #OP_EINVAL The source is not seekable (so we can't know the length),
|
||||
\retval #OP_EINVAL The stream is not seekable (so we can't know the length),
|
||||
\a _li wasn't less than the total number of links in
|
||||
the stream, or the stream was only partially open.*/
|
||||
ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
||||
|
@ -1575,8 +1580,8 @@ const OpusTags *op_tags(const OggOpusFile *_of,int _li) OP_ARG_NONNULL(1);
|
|||
\param _of The \c OggOpusFile from which to retrieve the current link index.
|
||||
\return The index of the current link on success, or a negative value on
|
||||
failure.
|
||||
For seekable streams, this is a number between 0 and the value
|
||||
returned by op_link_count().
|
||||
For seekable streams, this is a number between 0 (inclusive) and the
|
||||
value returned by op_link_count() (exclusive).
|
||||
For unseekable streams, this value starts at 0 and increments by one
|
||||
each time a new link is encountered (even though op_link_count()
|
||||
always returns 1).
|
||||
|
@ -1640,10 +1645,10 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
/*@{*/
|
||||
/**\name Functions for seeking in Opus streams
|
||||
|
||||
These functions let you seek in Opus streams, if the underlying source
|
||||
These functions let you seek in Opus streams, if the underlying stream
|
||||
support it.
|
||||
Seeking is implemented for all built-in stream I/O routines, though some
|
||||
individual sources may not be seekable (pipes, live HTTP streams, or HTTP
|
||||
individual streams may not be seekable (pipes, live HTTP streams, or HTTP
|
||||
streams from a server that does not support <code>Range</code> requests).
|
||||
|
||||
op_raw_seek() is the fastest: it is guaranteed to perform at most one
|
||||
|
@ -1670,6 +1675,8 @@ ogg_int64_t op_pcm_tell(const OggOpusFile *_of) OP_ARG_NONNULL(1);
|
|||
packets out of the tail of the link to which it seeks.
|
||||
\param _of The \c OggOpusFile in which to seek.
|
||||
\param _byte_offset The byte position to seek to.
|
||||
This must be between 0 and #op_raw_total(\a _of,\c -1)
|
||||
(inclusive).
|
||||
\return 0 on success, or a negative error code on failure.
|
||||
\retval #OP_EREAD The underlying seek operation failed.
|
||||
\retval #OP_EINVAL The stream was only partially open, or the target was
|
||||
|
|
|
@ -363,6 +363,9 @@ int main(int _argc,const char **_argv){
|
|||
Ef*=Ef;
|
||||
err+=Ef*Ef;
|
||||
}
|
||||
free(xb);
|
||||
free(X);
|
||||
free(Y);
|
||||
err=pow(err/nframes,1.0/16);
|
||||
Q=100*(1-0.5*log(1+err)/log(1.13));
|
||||
if(Q<0){
|
||||
|
|
|
@ -78,6 +78,26 @@ struct OpusDecoder {
|
|||
opus_uint32 rangeFinal;
|
||||
};
|
||||
|
||||
#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS)
|
||||
static void validate_opus_decoder(OpusDecoder *st)
|
||||
{
|
||||
celt_assert(st->channels == 1 || st->channels == 2);
|
||||
celt_assert(st->Fs == 48000 || st->Fs == 24000 || st->Fs == 16000 || st->Fs == 12000 || st->Fs == 8000);
|
||||
celt_assert(st->DecControl.API_sampleRate == st->Fs);
|
||||
celt_assert(st->DecControl.internalSampleRate == 0 || st->DecControl.internalSampleRate == 16000 || st->DecControl.internalSampleRate == 12000 || st->DecControl.internalSampleRate == 8000);
|
||||
celt_assert(st->DecControl.nChannelsAPI == st->channels);
|
||||
celt_assert(st->DecControl.nChannelsInternal == 0 || st->DecControl.nChannelsInternal == 1 || st->DecControl.nChannelsInternal == 2);
|
||||
celt_assert(st->DecControl.payloadSize_ms == 0 || st->DecControl.payloadSize_ms == 10 || st->DecControl.payloadSize_ms == 20 || st->DecControl.payloadSize_ms == 40 || st->DecControl.payloadSize_ms == 60);
|
||||
#ifdef OPUS_ARCHMASK
|
||||
celt_assert(st->arch >= 0);
|
||||
celt_assert(st->arch <= OPUS_ARCHMASK);
|
||||
#endif
|
||||
celt_assert(st->stream_channels == 1 || st->stream_channels == 2);
|
||||
}
|
||||
#define VALIDATE_OPUS_DECODER(st) validate_opus_decoder(st)
|
||||
#else
|
||||
#define VALIDATE_OPUS_DECODER(st)
|
||||
#endif
|
||||
|
||||
int opus_decoder_get_size(int channels)
|
||||
{
|
||||
|
@ -104,7 +124,7 @@ int opus_decoder_init(OpusDecoder *st, opus_int32 Fs, int channels)
|
|||
return OPUS_BAD_ARG;
|
||||
|
||||
OPUS_CLEAR((char*)st, opus_decoder_get_size(channels));
|
||||
/* Initialize SILK encoder */
|
||||
/* Initialize SILK decoder */
|
||||
ret = silk_Get_Decoder_Size(&silkDecSizeBytes);
|
||||
if (ret)
|
||||
return OPUS_INTERNAL_ERROR;
|
||||
|
@ -217,6 +237,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
|
||||
int audiosize;
|
||||
int mode;
|
||||
int bandwidth;
|
||||
int transition=0;
|
||||
int start_band;
|
||||
int redundancy=0;
|
||||
|
@ -253,10 +274,12 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
{
|
||||
audiosize = st->frame_size;
|
||||
mode = st->mode;
|
||||
bandwidth = st->bandwidth;
|
||||
ec_dec_init(&dec,(unsigned char*)data,len);
|
||||
} else {
|
||||
audiosize = frame_size;
|
||||
mode = st->prev_mode;
|
||||
bandwidth = 0;
|
||||
|
||||
if (mode == 0)
|
||||
{
|
||||
|
@ -355,15 +378,15 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
{
|
||||
st->DecControl.nChannelsInternal = st->stream_channels;
|
||||
if( mode == MODE_SILK_ONLY ) {
|
||||
if( st->bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
|
||||
if( bandwidth == OPUS_BANDWIDTH_NARROWBAND ) {
|
||||
st->DecControl.internalSampleRate = 8000;
|
||||
} else if( st->bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
|
||||
} else if( bandwidth == OPUS_BANDWIDTH_MEDIUMBAND ) {
|
||||
st->DecControl.internalSampleRate = 12000;
|
||||
} else if( st->bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
|
||||
} else if( bandwidth == OPUS_BANDWIDTH_WIDEBAND ) {
|
||||
st->DecControl.internalSampleRate = 16000;
|
||||
} else {
|
||||
st->DecControl.internalSampleRate = 16000;
|
||||
silk_assert( 0 );
|
||||
celt_assert( 0 );
|
||||
}
|
||||
} else {
|
||||
/* Hybrid mode */
|
||||
|
@ -427,29 +450,6 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
if (mode != MODE_CELT_ONLY)
|
||||
start_band = 17;
|
||||
|
||||
{
|
||||
int endband=21;
|
||||
|
||||
switch(st->bandwidth)
|
||||
{
|
||||
case OPUS_BANDWIDTH_NARROWBAND:
|
||||
endband = 13;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_MEDIUMBAND:
|
||||
case OPUS_BANDWIDTH_WIDEBAND:
|
||||
endband = 17;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_SUPERWIDEBAND:
|
||||
endband = 19;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_FULLBAND:
|
||||
endband = 21;
|
||||
break;
|
||||
}
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband));
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels));
|
||||
}
|
||||
|
||||
if (redundancy)
|
||||
{
|
||||
transition = 0;
|
||||
|
@ -464,6 +464,34 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
|
||||
}
|
||||
|
||||
|
||||
if (bandwidth)
|
||||
{
|
||||
int endband=21;
|
||||
|
||||
switch(bandwidth)
|
||||
{
|
||||
case OPUS_BANDWIDTH_NARROWBAND:
|
||||
endband = 13;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_MEDIUMBAND:
|
||||
case OPUS_BANDWIDTH_WIDEBAND:
|
||||
endband = 17;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_SUPERWIDEBAND:
|
||||
endband = 19;
|
||||
break;
|
||||
case OPUS_BANDWIDTH_FULLBAND:
|
||||
endband = 21;
|
||||
break;
|
||||
default:
|
||||
celt_assert(0);
|
||||
break;
|
||||
}
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_END_BAND(endband)));
|
||||
}
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_CHANNELS(st->stream_channels)));
|
||||
|
||||
/* Only allocation memory for redundancy if/when needed */
|
||||
redundant_audio_size = redundancy ? F5*st->channels : ALLOC_NONE;
|
||||
ALLOC(redundant_audio, redundant_audio_size, opus_val16);
|
||||
|
@ -471,21 +499,21 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
/* 5 ms redundant frame for CELT->SILK*/
|
||||
if (redundancy && celt_to_silk)
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)));
|
||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes,
|
||||
redundant_audio, F5, NULL, 0);
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)));
|
||||
}
|
||||
|
||||
/* MUST be after PLC */
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(start_band)));
|
||||
|
||||
if (mode != MODE_SILK_ONLY)
|
||||
{
|
||||
int celt_frame_size = IMIN(F20, frame_size);
|
||||
/* Make sure to discard any previous CELT state */
|
||||
if (mode != st->prev_mode && st->prev_mode > 0 && !st->prev_redundancy)
|
||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE));
|
||||
/* Decode CELT */
|
||||
celt_ret = celt_decode_with_ec(celt_dec, decode_fec ? NULL : data,
|
||||
len, pcm, celt_frame_size, &dec, celt_accum);
|
||||
|
@ -500,7 +528,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
do a fade-out by decoding a silence frame */
|
||||
if (st->prev_mode == MODE_HYBRID && !(redundancy && celt_to_silk && st->prev_redundancy) )
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)));
|
||||
celt_decode_with_ec(celt_dec, silence, 2, pcm, F2_5, NULL, celt_accum);
|
||||
}
|
||||
}
|
||||
|
@ -518,18 +546,18 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
|
|||
|
||||
{
|
||||
const CELTMode *celt_mode;
|
||||
celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode)));
|
||||
window = celt_mode->window;
|
||||
}
|
||||
|
||||
/* 5 ms redundant frame for SILK->CELT */
|
||||
if (redundancy && !celt_to_silk)
|
||||
{
|
||||
celt_decoder_ctl(celt_dec, OPUS_RESET_STATE);
|
||||
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_RESET_STATE));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)));
|
||||
|
||||
celt_decode_with_ec(celt_dec, data+len, redundancy_bytes, redundant_audio, F5, NULL, 0);
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng));
|
||||
MUST_SUCCEED(celt_decoder_ctl(celt_dec, OPUS_GET_FINAL_RANGE(&redundant_rng)));
|
||||
smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
|
||||
pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
|
||||
}
|
||||
|
@ -605,6 +633,7 @@ int opus_decode_native(OpusDecoder *st, const unsigned char *data,
|
|||
int packet_frame_size, packet_bandwidth, packet_mode, packet_stream_channels;
|
||||
/* 48 x 2.5 ms = 120 ms */
|
||||
opus_int16 size[48];
|
||||
VALIDATE_OPUS_DECODER(st);
|
||||
if (decode_fec<0 || decode_fec>1)
|
||||
return OPUS_BAD_ARG;
|
||||
/* For FEC/PLC, frame_size has to be to have a multiple of 2.5 ms */
|
||||
|
@ -740,6 +769,7 @@ int opus_decode_float(OpusDecoder *st, const unsigned char *data,
|
|||
else
|
||||
return OPUS_INVALID_PACKET;
|
||||
}
|
||||
celt_assert(st->channels == 1 || st->channels == 2);
|
||||
ALLOC(out, frame_size*st->channels, opus_int16);
|
||||
|
||||
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 0);
|
||||
|
@ -777,6 +807,7 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
|
|||
else
|
||||
return OPUS_INVALID_PACKET;
|
||||
}
|
||||
celt_assert(st->channels == 1 || st->channels == 2);
|
||||
ALLOC(out, frame_size*st->channels, float);
|
||||
|
||||
ret = opus_decode_native(st, data, len, out, frame_size, decode_fec, 0, NULL, 1);
|
||||
|
@ -864,7 +895,7 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
|||
goto bad_arg;
|
||||
}
|
||||
if (st->prev_mode == MODE_CELT_ONLY)
|
||||
celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
|
||||
ret = celt_decoder_ctl(celt_dec, OPUS_GET_PITCH(value));
|
||||
else
|
||||
*value = st->DecControl.prevPitchLag;
|
||||
}
|
||||
|
@ -891,7 +922,7 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
|||
break;
|
||||
case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
|
||||
{
|
||||
opus_uint32 *value = va_arg(ap, opus_uint32*);
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
|
@ -899,6 +930,26 @@ int opus_decoder_ctl(OpusDecoder *st, int request, ...)
|
|||
*value = st->last_packet_duration;
|
||||
}
|
||||
break;
|
||||
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 value = va_arg(ap, opus_int32);
|
||||
if(value<0 || value>1)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
ret = celt_decoder_ctl(celt_dec, OPUS_SET_PHASE_INVERSION_DISABLED(value));
|
||||
}
|
||||
break;
|
||||
case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
ret = celt_decoder_ctl(celt_dec, OPUS_GET_PHASE_INVERSION_DISABLED(value));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/*fprintf(stderr, "unknown opus_decoder_ctl() request: %d", request);*/
|
||||
ret = OPUS_UNIMPLEMENTED;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -37,16 +37,19 @@
|
|||
#include "float_cast.h"
|
||||
#include "os_support.h"
|
||||
|
||||
struct OpusMSDecoder {
|
||||
ChannelLayout layout;
|
||||
/* Decoder states go here */
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/* DECODER */
|
||||
|
||||
#if defined(ENABLE_HARDENING) || defined(ENABLE_ASSERTIONS)
|
||||
static void validate_ms_decoder(OpusMSDecoder *st)
|
||||
{
|
||||
validate_layout(&st->layout);
|
||||
}
|
||||
#define VALIDATE_MS_DECODER(st) validate_ms_decoder(st)
|
||||
#else
|
||||
#define VALIDATE_MS_DECODER(st)
|
||||
#endif
|
||||
|
||||
|
||||
opus_int32 opus_multistream_decoder_get_size(int nb_streams, int nb_coupled_streams)
|
||||
{
|
||||
int coupled_size;
|
||||
|
@ -143,15 +146,6 @@ OpusMSDecoder *opus_multistream_decoder_create(
|
|||
return st;
|
||||
}
|
||||
|
||||
typedef void (*opus_copy_channel_out_func)(
|
||||
void *dst,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
static int opus_multistream_packet_validate(const unsigned char *data,
|
||||
opus_int32 len, int nb_streams, opus_int32 Fs)
|
||||
{
|
||||
|
@ -181,7 +175,7 @@ static int opus_multistream_packet_validate(const unsigned char *data,
|
|||
return samples;
|
||||
}
|
||||
|
||||
static int opus_multistream_decode_native(
|
||||
int opus_multistream_decode_native(
|
||||
OpusMSDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
|
@ -189,7 +183,8 @@ static int opus_multistream_decode_native(
|
|||
opus_copy_channel_out_func copy_channel_out,
|
||||
int frame_size,
|
||||
int decode_fec,
|
||||
int soft_clip
|
||||
int soft_clip,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
opus_int32 Fs;
|
||||
|
@ -201,8 +196,14 @@ static int opus_multistream_decode_native(
|
|||
VARDECL(opus_val16, buf);
|
||||
ALLOC_STACK;
|
||||
|
||||
VALIDATE_MS_DECODER(st);
|
||||
if (frame_size <= 0)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
/* Limit frame_size to avoid excessive stack allocations. */
|
||||
opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs));
|
||||
MUST_SUCCEED(opus_multistream_decoder_ctl(st, OPUS_GET_SAMPLE_RATE(&Fs)));
|
||||
frame_size = IMIN(frame_size, Fs/25*3);
|
||||
ALLOC(buf, 2*frame_size, opus_val16);
|
||||
ptr = (char*)st + align(sizeof(OpusMSDecoder));
|
||||
|
@ -237,7 +238,8 @@ static int opus_multistream_decode_native(
|
|||
for (s=0;s<st->layout.nb_streams;s++)
|
||||
{
|
||||
OpusDecoder *dec;
|
||||
int packet_offset, ret;
|
||||
opus_int32 packet_offset;
|
||||
int ret;
|
||||
|
||||
dec = (OpusDecoder*)ptr;
|
||||
ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
|
||||
|
@ -265,7 +267,7 @@ static int opus_multistream_decode_native(
|
|||
while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
|
||||
{
|
||||
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
|
||||
buf, 2, frame_size);
|
||||
buf, 2, frame_size, user_data);
|
||||
prev = chan;
|
||||
}
|
||||
prev = -1;
|
||||
|
@ -273,7 +275,7 @@ static int opus_multistream_decode_native(
|
|||
while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
|
||||
{
|
||||
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
|
||||
buf+1, 2, frame_size);
|
||||
buf+1, 2, frame_size, user_data);
|
||||
prev = chan;
|
||||
}
|
||||
} else {
|
||||
|
@ -283,7 +285,7 @@ static int opus_multistream_decode_native(
|
|||
while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
|
||||
{
|
||||
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
|
||||
buf, 1, frame_size);
|
||||
buf, 1, frame_size, user_data);
|
||||
prev = chan;
|
||||
}
|
||||
}
|
||||
|
@ -294,7 +296,7 @@ static int opus_multistream_decode_native(
|
|||
if (st->layout.mapping[c] == 255)
|
||||
{
|
||||
(*copy_channel_out)(pcm, st->layout.nb_channels, c,
|
||||
NULL, 0, frame_size);
|
||||
NULL, 0, frame_size, user_data);
|
||||
}
|
||||
}
|
||||
RESTORE_STACK;
|
||||
|
@ -308,11 +310,13 @@ static void opus_copy_channel_out_float(
|
|||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
float *float_dst;
|
||||
opus_int32 i;
|
||||
(void)user_data;
|
||||
float_dst = (float*)dst;
|
||||
if (src != NULL)
|
||||
{
|
||||
|
@ -337,11 +341,13 @@ static void opus_copy_channel_out_short(
|
|||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
opus_int16 *short_dst;
|
||||
opus_int32 i;
|
||||
(void)user_data;
|
||||
short_dst = (opus_int16*)dst;
|
||||
if (src != NULL)
|
||||
{
|
||||
|
@ -372,7 +378,7 @@ int opus_multistream_decode(
|
|||
)
|
||||
{
|
||||
return opus_multistream_decode_native(st, data, len,
|
||||
pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0);
|
||||
pcm, opus_copy_channel_out_short, frame_size, decode_fec, 0, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
|
@ -380,7 +386,7 @@ int opus_multistream_decode_float(OpusMSDecoder *st, const unsigned char *data,
|
|||
opus_int32 len, float *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native(st, data, len,
|
||||
pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
|
||||
pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -390,32 +396,30 @@ int opus_multistream_decode(OpusMSDecoder *st, const unsigned char *data,
|
|||
opus_int32 len, opus_int16 *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native(st, data, len,
|
||||
pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1);
|
||||
pcm, opus_copy_channel_out_short, frame_size, decode_fec, 1, NULL);
|
||||
}
|
||||
|
||||
int opus_multistream_decode_float(
|
||||
OpusMSDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
float *pcm,
|
||||
opus_val16 *pcm,
|
||||
int frame_size,
|
||||
int decode_fec
|
||||
)
|
||||
{
|
||||
return opus_multistream_decode_native(st, data, len,
|
||||
pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0);
|
||||
pcm, opus_copy_channel_out_float, frame_size, decode_fec, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
||||
int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request,
|
||||
va_list ap)
|
||||
{
|
||||
va_list ap;
|
||||
int coupled_size, mono_size;
|
||||
char *ptr;
|
||||
int ret = OPUS_OK;
|
||||
|
||||
va_start(ap, request);
|
||||
|
||||
coupled_size = opus_decoder_get_size(2);
|
||||
mono_size = opus_decoder_get_size(1);
|
||||
ptr = (char*)st + align(sizeof(OpusMSDecoder));
|
||||
|
@ -425,6 +429,7 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
|||
case OPUS_GET_SAMPLE_RATE_REQUEST:
|
||||
case OPUS_GET_GAIN_REQUEST:
|
||||
case OPUS_GET_LAST_PACKET_DURATION_REQUEST:
|
||||
case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
OpusDecoder *dec;
|
||||
/* For int32* GET params, just query the first stream */
|
||||
|
@ -482,7 +487,7 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
|||
OpusDecoder **value;
|
||||
stream_id = va_arg(ap, opus_int32);
|
||||
if (stream_id<0 || stream_id >= st->layout.nb_streams)
|
||||
ret = OPUS_BAD_ARG;
|
||||
goto bad_arg;
|
||||
value = va_arg(ap, OpusDecoder**);
|
||||
if (!value)
|
||||
{
|
||||
|
@ -499,6 +504,7 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
|||
}
|
||||
break;
|
||||
case OPUS_SET_GAIN_REQUEST:
|
||||
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
int s;
|
||||
/* This works for int32 params */
|
||||
|
@ -522,14 +528,20 @@ int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
|||
ret = OPUS_UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return ret;
|
||||
bad_arg:
|
||||
va_end(ap);
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
int opus_multistream_decoder_ctl(OpusMSDecoder *st, int request, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, request);
|
||||
ret = opus_multistream_decoder_ctl_va_list(st, request, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void opus_multistream_decoder_destroy(OpusMSDecoder *st)
|
||||
{
|
||||
|
|
|
@ -61,38 +61,6 @@ static const VorbisLayout vorbis_mappings[8] = {
|
|||
{5, 3, {0, 6, 1, 2, 3, 4, 5, 7}}, /* 8: 7.1 surround */
|
||||
};
|
||||
|
||||
typedef void (*opus_copy_channel_in_func)(
|
||||
opus_val16 *dst,
|
||||
int dst_stride,
|
||||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size
|
||||
);
|
||||
|
||||
typedef enum {
|
||||
MAPPING_TYPE_NONE,
|
||||
MAPPING_TYPE_SURROUND
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
, /* Do not include comma at end of enumerator list */
|
||||
MAPPING_TYPE_AMBISONICS
|
||||
#endif
|
||||
} MappingType;
|
||||
|
||||
struct OpusMSEncoder {
|
||||
ChannelLayout layout;
|
||||
int arch;
|
||||
int lfe_stream;
|
||||
int application;
|
||||
int variable_duration;
|
||||
MappingType mapping_type;
|
||||
opus_int32 bitrate_bps;
|
||||
float subframe_mem[3];
|
||||
/* Encoder states go here */
|
||||
/* then opus_val32 window_mem[channels*120]; */
|
||||
/* then opus_val32 preemph_mem[channels]; */
|
||||
};
|
||||
|
||||
static opus_val32 *ms_get_preemph_mem(OpusMSEncoder *st)
|
||||
{
|
||||
int s;
|
||||
|
@ -133,6 +101,29 @@ static opus_val32 *ms_get_window_mem(OpusMSEncoder *st)
|
|||
return (opus_val32*)(void*)ptr;
|
||||
}
|
||||
|
||||
static int validate_ambisonics(int nb_channels, int *nb_streams, int *nb_coupled_streams)
|
||||
{
|
||||
int order_plus_one;
|
||||
int acn_channels;
|
||||
int nondiegetic_channels;
|
||||
|
||||
if (nb_channels < 1 || nb_channels > 227)
|
||||
return 0;
|
||||
|
||||
order_plus_one = isqrt32(nb_channels);
|
||||
acn_channels = order_plus_one * order_plus_one;
|
||||
nondiegetic_channels = nb_channels - acn_channels;
|
||||
|
||||
if (nondiegetic_channels != 0 && nondiegetic_channels != 2)
|
||||
return 0;
|
||||
|
||||
if (nb_streams)
|
||||
*nb_streams = acn_channels + (nondiegetic_channels != 0);
|
||||
if (nb_coupled_streams)
|
||||
*nb_coupled_streams = nondiegetic_channels != 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int validate_encoder_layout(const ChannelLayout *layout)
|
||||
{
|
||||
int s;
|
||||
|
@ -240,6 +231,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
|
|||
int pos[8] = {0};
|
||||
int upsample;
|
||||
int frame_size;
|
||||
int freq_size;
|
||||
opus_val16 channel_offset;
|
||||
opus_val32 bandE[21];
|
||||
opus_val16 maskLogE[3][21];
|
||||
|
@ -250,6 +242,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
|
|||
|
||||
upsample = resampling_factor(rate);
|
||||
frame_size = len*upsample;
|
||||
freq_size = IMIN(960, frame_size);
|
||||
|
||||
/* LM = log2(frame_size / 120) */
|
||||
for (LM=0;LM<celt_mode->maxLM;LM++)
|
||||
|
@ -258,7 +251,7 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
|
|||
|
||||
ALLOC(in, frame_size+overlap, opus_val32);
|
||||
ALLOC(x, len, opus_val16);
|
||||
ALLOC(freq, frame_size, opus_val32);
|
||||
ALLOC(freq, freq_size, opus_val32);
|
||||
|
||||
channel_pos(channels, pos);
|
||||
|
||||
|
@ -268,8 +261,11 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
|
|||
|
||||
for (c=0;c<channels;c++)
|
||||
{
|
||||
int frame;
|
||||
int nb_frames = frame_size/freq_size;
|
||||
celt_assert(nb_frames*freq_size == frame_size);
|
||||
OPUS_COPY(in, mem+c*overlap, overlap);
|
||||
(*copy_channel_in)(x, 1, pcm, channels, c, len);
|
||||
(*copy_channel_in)(x, 1, pcm, channels, c, len, NULL);
|
||||
celt_preemphasis(x, in+overlap, frame_size, 1, upsample, celt_mode->preemph, preemph_mem+c, 0);
|
||||
#ifndef FIXED_POINT
|
||||
{
|
||||
|
@ -284,18 +280,26 @@ void surround_analysis(const CELTMode *celt_mode, const void *pcm, opus_val16 *b
|
|||
}
|
||||
}
|
||||
#endif
|
||||
clt_mdct_forward(&celt_mode->mdct, in, freq, celt_mode->window,
|
||||
overlap, celt_mode->maxLM-LM, 1, arch);
|
||||
if (upsample != 1)
|
||||
OPUS_CLEAR(bandE, 21);
|
||||
for (frame=0;frame<nb_frames;frame++)
|
||||
{
|
||||
int bound = len;
|
||||
for (i=0;i<bound;i++)
|
||||
freq[i] *= upsample;
|
||||
for (;i<frame_size;i++)
|
||||
freq[i] = 0;
|
||||
}
|
||||
opus_val32 tmpE[21];
|
||||
clt_mdct_forward(&celt_mode->mdct, in+960*frame, freq, celt_mode->window,
|
||||
overlap, celt_mode->maxLM-LM, 1, arch);
|
||||
if (upsample != 1)
|
||||
{
|
||||
int bound = freq_size/upsample;
|
||||
for (i=0;i<bound;i++)
|
||||
freq[i] *= upsample;
|
||||
for (;i<freq_size;i++)
|
||||
freq[i] = 0;
|
||||
}
|
||||
|
||||
compute_band_energies(celt_mode, freq, bandE, 21, 1, LM);
|
||||
compute_band_energies(celt_mode, freq, tmpE, 21, 1, LM, arch);
|
||||
/* If we have multiple frames, take the max energy. */
|
||||
for (i=0;i<21;i++)
|
||||
bandE[i] = MAX32(bandE[i], tmpE[i]);
|
||||
}
|
||||
amp2Log2(celt_mode, 21, 21, bandE, bandLogE+21*c, 1);
|
||||
/* Apply spreading function with -6 dB/band going up and -12 dB/band going down. */
|
||||
for (i=1;i<21;i++)
|
||||
|
@ -408,12 +412,10 @@ opus_int32 opus_multistream_surround_encoder_get_size(int channels, int mapping_
|
|||
{
|
||||
nb_streams=channels;
|
||||
nb_coupled_streams=0;
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
} else if (mapping_family==254)
|
||||
} else if (mapping_family==2)
|
||||
{
|
||||
nb_streams=channels;
|
||||
nb_coupled_streams=0;
|
||||
#endif
|
||||
if (!validate_ambisonics(channels, &nb_streams, &nb_coupled_streams))
|
||||
return 0;
|
||||
} else
|
||||
return 0;
|
||||
size = opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
|
||||
|
@ -448,7 +450,6 @@ static int opus_multistream_encoder_init_impl(
|
|||
st->layout.nb_channels = channels;
|
||||
st->layout.nb_streams = streams;
|
||||
st->layout.nb_coupled_streams = coupled_streams;
|
||||
st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
|
||||
if (mapping_type != MAPPING_TYPE_SURROUND)
|
||||
st->lfe_stream = -1;
|
||||
st->bitrate_bps = OPUS_AUTO;
|
||||
|
@ -456,7 +457,13 @@ static int opus_multistream_encoder_init_impl(
|
|||
st->variable_duration = OPUS_FRAMESIZE_ARG;
|
||||
for (i=0;i<st->layout.nb_channels;i++)
|
||||
st->layout.mapping[i] = mapping[i];
|
||||
if (!validate_layout(&st->layout) || !validate_encoder_layout(&st->layout))
|
||||
if (!validate_layout(&st->layout))
|
||||
return OPUS_BAD_ARG;
|
||||
if (mapping_type == MAPPING_TYPE_SURROUND &&
|
||||
!validate_encoder_layout(&st->layout))
|
||||
return OPUS_BAD_ARG;
|
||||
if (mapping_type == MAPPING_TYPE_AMBISONICS &&
|
||||
!validate_ambisonics(st->layout.nb_channels, NULL, NULL))
|
||||
return OPUS_BAD_ARG;
|
||||
ptr = (char*)st + align(sizeof(OpusMSEncoder));
|
||||
coupled_size = opus_encoder_get_size(2);
|
||||
|
@ -549,25 +556,23 @@ int opus_multistream_surround_encoder_init(
|
|||
*coupled_streams=0;
|
||||
for(i=0;i<channels;i++)
|
||||
mapping[i] = i;
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
} else if (mapping_family==254)
|
||||
} else if (mapping_family==2)
|
||||
{
|
||||
int i;
|
||||
*streams=channels;
|
||||
*coupled_streams=0;
|
||||
for(i=0;i<channels;i++)
|
||||
mapping[i] = i;
|
||||
#endif
|
||||
if (!validate_ambisonics(channels, streams, coupled_streams))
|
||||
return OPUS_BAD_ARG;
|
||||
for(i = 0; i < (*streams - *coupled_streams); i++)
|
||||
mapping[i] = i + (*coupled_streams * 2);
|
||||
for(i = 0; i < *coupled_streams * 2; i++)
|
||||
mapping[i + (*streams - *coupled_streams)] = i;
|
||||
} else
|
||||
return OPUS_UNIMPLEMENTED;
|
||||
|
||||
if (channels>2 && mapping_family==1) {
|
||||
mapping_type = MAPPING_TYPE_SURROUND;
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
} else if (mapping_family==254)
|
||||
} else if (mapping_family==2)
|
||||
{
|
||||
mapping_type = MAPPING_TYPE_AMBISONICS;
|
||||
#endif
|
||||
} else
|
||||
{
|
||||
mapping_type = MAPPING_TYPE_NONE;
|
||||
|
@ -672,62 +677,62 @@ static void surround_rate_allocation(
|
|||
int lfe_offset;
|
||||
int coupled_ratio; /* Q8 */
|
||||
int lfe_ratio; /* Q8 */
|
||||
int nb_lfe;
|
||||
int nb_uncoupled;
|
||||
int nb_coupled;
|
||||
int nb_normal;
|
||||
opus_int32 channel_offset;
|
||||
opus_int32 bitrate;
|
||||
int total;
|
||||
|
||||
if (st->bitrate_bps > st->layout.nb_channels*40000)
|
||||
stream_offset = 20000;
|
||||
else
|
||||
stream_offset = st->bitrate_bps/st->layout.nb_channels/2;
|
||||
stream_offset += 60*(Fs/frame_size-50);
|
||||
/* We start by giving each stream (coupled or uncoupled) the same bitrate.
|
||||
nb_lfe = (st->lfe_stream!=-1);
|
||||
nb_coupled = st->layout.nb_coupled_streams;
|
||||
nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
|
||||
nb_normal = 2*nb_coupled + nb_uncoupled;
|
||||
|
||||
/* Give each non-LFE channel enough bits per channel for coding band energy. */
|
||||
channel_offset = 40*IMAX(50, Fs/frame_size);
|
||||
|
||||
if (st->bitrate_bps==OPUS_AUTO)
|
||||
{
|
||||
bitrate = nb_normal*(channel_offset + Fs + 10000) + 8000*nb_lfe;
|
||||
} else if (st->bitrate_bps==OPUS_BITRATE_MAX)
|
||||
{
|
||||
bitrate = nb_normal*300000 + nb_lfe*128000;
|
||||
} else {
|
||||
bitrate = st->bitrate_bps;
|
||||
}
|
||||
|
||||
/* Give LFE some basic stream_channel allocation but never exceed 1/20 of the
|
||||
total rate for the non-energy part to avoid problems at really low rate. */
|
||||
lfe_offset = IMIN(bitrate/20, 3000) + 15*IMAX(50, Fs/frame_size);
|
||||
|
||||
/* We give each stream (coupled or uncoupled) a starting bitrate.
|
||||
This models the main saving of coupled channels over uncoupled. */
|
||||
/* The LFE stream is an exception to the above and gets fewer bits. */
|
||||
lfe_offset = 3500 + 60*(Fs/frame_size-50);
|
||||
/* Coupled streams get twice the mono rate after the first 20 kb/s. */
|
||||
stream_offset = (bitrate - channel_offset*nb_normal - lfe_offset*nb_lfe)/nb_normal/2;
|
||||
stream_offset = IMAX(0, IMIN(20000, stream_offset));
|
||||
|
||||
/* Coupled streams get twice the mono rate after the offset is allocated. */
|
||||
coupled_ratio = 512;
|
||||
/* Should depend on the bitrate, for now we assume LFE gets 1/8 the bits of mono */
|
||||
lfe_ratio = 32;
|
||||
|
||||
/* Compute bitrate allocation between streams */
|
||||
if (st->bitrate_bps==OPUS_AUTO)
|
||||
{
|
||||
channel_rate = Fs+60*Fs/frame_size;
|
||||
} else if (st->bitrate_bps==OPUS_BITRATE_MAX)
|
||||
{
|
||||
channel_rate = 300000;
|
||||
} else {
|
||||
int nb_lfe;
|
||||
int nb_uncoupled;
|
||||
int nb_coupled;
|
||||
int total;
|
||||
nb_lfe = (st->lfe_stream!=-1);
|
||||
nb_coupled = st->layout.nb_coupled_streams;
|
||||
nb_uncoupled = st->layout.nb_streams-nb_coupled-nb_lfe;
|
||||
total = (nb_uncoupled<<8) /* mono */
|
||||
+ coupled_ratio*nb_coupled /* stereo */
|
||||
+ nb_lfe*lfe_ratio;
|
||||
channel_rate = 256*(st->bitrate_bps-lfe_offset*nb_lfe-stream_offset*(nb_coupled+nb_uncoupled))/total;
|
||||
}
|
||||
#ifndef FIXED_POINT
|
||||
if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
|
||||
{
|
||||
opus_int32 bonus;
|
||||
bonus = 60*(Fs/frame_size-50);
|
||||
channel_rate += bonus;
|
||||
}
|
||||
#endif
|
||||
total = (nb_uncoupled<<8) /* mono */
|
||||
+ coupled_ratio*nb_coupled /* stereo */
|
||||
+ nb_lfe*lfe_ratio;
|
||||
channel_rate = 256*(opus_int64)(bitrate - lfe_offset*nb_lfe - stream_offset*(nb_coupled+nb_uncoupled) - channel_offset*nb_normal)/total;
|
||||
|
||||
for (i=0;i<st->layout.nb_streams;i++)
|
||||
{
|
||||
if (i<st->layout.nb_coupled_streams)
|
||||
rate[i] = stream_offset+(channel_rate*coupled_ratio>>8);
|
||||
rate[i] = 2*channel_offset + IMAX(0, stream_offset+(channel_rate*coupled_ratio>>8));
|
||||
else if (i!=st->lfe_stream)
|
||||
rate[i] = stream_offset+channel_rate;
|
||||
rate[i] = channel_offset + IMAX(0, stream_offset + channel_rate);
|
||||
else
|
||||
rate[i] = lfe_offset+(channel_rate*lfe_ratio>>8);
|
||||
rate[i] = IMAX(0, lfe_offset+(channel_rate*lfe_ratio>>8));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
static void ambisonics_rate_allocation(
|
||||
OpusMSEncoder *st,
|
||||
opus_int32 *rate,
|
||||
|
@ -736,50 +741,31 @@ static void ambisonics_rate_allocation(
|
|||
)
|
||||
{
|
||||
int i;
|
||||
int non_mono_rate;
|
||||
int total_rate;
|
||||
opus_int32 total_rate;
|
||||
opus_int32 per_stream_rate;
|
||||
|
||||
/* The mono channel gets (rate_ratio_num / rate_ratio_den) times as many bits
|
||||
* as all other channels */
|
||||
const int rate_ratio_num = 4;
|
||||
const int rate_ratio_den = 3;
|
||||
const int num_channels = st->layout.nb_streams;
|
||||
const int nb_channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
|
||||
|
||||
if (st->bitrate_bps==OPUS_AUTO)
|
||||
{
|
||||
total_rate = num_channels * (20000 + st->layout.nb_streams*(Fs+60*Fs/frame_size));
|
||||
total_rate = (st->layout.nb_coupled_streams + st->layout.nb_streams) *
|
||||
(Fs+60*Fs/frame_size) + st->layout.nb_streams * (opus_int32)15000;
|
||||
} else if (st->bitrate_bps==OPUS_BITRATE_MAX)
|
||||
{
|
||||
total_rate = num_channels * 320000;
|
||||
} else {
|
||||
total_rate = nb_channels * 320000;
|
||||
} else
|
||||
{
|
||||
total_rate = st->bitrate_bps;
|
||||
}
|
||||
|
||||
/* Let y be the non-mono rate and let p, q be integers such that the mono
|
||||
* channel rate is (p/q) * y.
|
||||
* Also let T be the total bitrate to allocate. Then
|
||||
* (n - 1) y + (p/q) y = T
|
||||
* y = (T q) / (qn - q + p)
|
||||
*/
|
||||
non_mono_rate =
|
||||
total_rate * rate_ratio_den
|
||||
/ (rate_ratio_den*num_channels + rate_ratio_num - rate_ratio_den);
|
||||
|
||||
#ifndef FIXED_POINT
|
||||
if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != Fs/50)
|
||||
/* Allocate equal number of bits to Ambisonic (uncoupled) and non-diegetic
|
||||
* (coupled) streams */
|
||||
per_stream_rate = total_rate / st->layout.nb_streams;
|
||||
for (i = 0; i < st->layout.nb_streams; i++)
|
||||
{
|
||||
opus_int32 bonus = 60*(Fs/frame_size-50);
|
||||
non_mono_rate += bonus;
|
||||
}
|
||||
#endif
|
||||
|
||||
rate[0] = total_rate - (num_channels - 1) * non_mono_rate;
|
||||
for (i=1;i<st->layout.nb_streams;i++)
|
||||
{
|
||||
rate[i] = non_mono_rate;
|
||||
rate[i] = per_stream_rate;
|
||||
}
|
||||
}
|
||||
#endif /* ENABLE_EXPERIMENTAL_AMBISONICS */
|
||||
|
||||
static opus_int32 rate_allocation(
|
||||
OpusMSEncoder *st,
|
||||
|
@ -795,11 +781,9 @@ static opus_int32 rate_allocation(
|
|||
ptr = (char*)st + align(sizeof(OpusMSEncoder));
|
||||
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_SAMPLE_RATE(&Fs));
|
||||
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
|
||||
ambisonics_rate_allocation(st, rate, frame_size, Fs);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
surround_rate_allocation(st, rate, frame_size, Fs);
|
||||
}
|
||||
|
@ -812,9 +796,9 @@ static opus_int32 rate_allocation(
|
|||
return rate_sum;
|
||||
}
|
||||
|
||||
/* Max size in case the encoder decides to return three frames */
|
||||
#define MS_FRAME_TMP (3*1275+7)
|
||||
static int opus_multistream_encode_native
|
||||
/* Max size in case the encoder decides to return six frames (6 x 20 ms = 120 ms) */
|
||||
#define MS_FRAME_TMP (6*1275+12)
|
||||
int opus_multistream_encode_native
|
||||
(
|
||||
OpusMSEncoder *st,
|
||||
opus_copy_channel_in_func copy_channel_in,
|
||||
|
@ -824,7 +808,8 @@ static int opus_multistream_encode_native
|
|||
opus_int32 max_data_bytes,
|
||||
int lsb_depth,
|
||||
downmix_func downmix,
|
||||
int float_api
|
||||
int float_api,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
opus_int32 Fs;
|
||||
|
@ -859,32 +844,8 @@ static int opus_multistream_encode_native
|
|||
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_VBR(&vbr));
|
||||
opus_encoder_ctl((OpusEncoder*)ptr, CELT_GET_MODE(&celt_mode));
|
||||
|
||||
{
|
||||
opus_int32 delay_compensation;
|
||||
int channels;
|
||||
|
||||
channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
|
||||
opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
|
||||
delay_compensation -= Fs/400;
|
||||
frame_size = compute_frame_size(pcm, analysis_frame_size,
|
||||
st->variable_duration, channels, Fs, st->bitrate_bps,
|
||||
delay_compensation, downmix
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
, st->subframe_mem
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
if (400*frame_size < Fs)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
/* Validate frame_size before using it to allocate stack space.
|
||||
This mirrors the checks in opus_encode[_float](). */
|
||||
if (400*frame_size != Fs && 200*frame_size != Fs &&
|
||||
100*frame_size != Fs && 50*frame_size != Fs &&
|
||||
25*frame_size != Fs && 50*frame_size != 3*Fs)
|
||||
frame_size = frame_size_select(analysis_frame_size, st->variable_duration, Fs);
|
||||
if (frame_size <= 0)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
|
@ -892,6 +853,9 @@ static int opus_multistream_encode_native
|
|||
|
||||
/* Smallest packet the encoder can produce. */
|
||||
smallest_packet = st->layout.nb_streams*2-1;
|
||||
/* 100 ms needs an extra byte per stream for the ToC. */
|
||||
if (Fs/frame_size == 10)
|
||||
smallest_packet += st->layout.nb_streams;
|
||||
if (max_data_bytes < smallest_packet)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
|
@ -952,11 +916,9 @@ static int opus_multistream_encode_native
|
|||
opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(2));
|
||||
}
|
||||
}
|
||||
#ifdef ENABLE_EXPERIMENTAL_AMBISONICS
|
||||
else if (st->mapping_type == MAPPING_TYPE_AMBISONICS) {
|
||||
opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ptr = (char*)st + align(sizeof(OpusMSEncoder));
|
||||
|
@ -979,9 +941,9 @@ static int opus_multistream_encode_native
|
|||
left = get_left_channel(&st->layout, s, -1);
|
||||
right = get_right_channel(&st->layout, s, -1);
|
||||
(*copy_channel_in)(buf, 2,
|
||||
pcm, st->layout.nb_channels, left, frame_size);
|
||||
pcm, st->layout.nb_channels, left, frame_size, user_data);
|
||||
(*copy_channel_in)(buf+1, 2,
|
||||
pcm, st->layout.nb_channels, right, frame_size);
|
||||
pcm, st->layout.nb_channels, right, frame_size, user_data);
|
||||
ptr += align(coupled_size);
|
||||
if (st->mapping_type == MAPPING_TYPE_SURROUND)
|
||||
{
|
||||
|
@ -997,7 +959,7 @@ static int opus_multistream_encode_native
|
|||
int i;
|
||||
int chan = get_mono_channel(&st->layout, s, -1);
|
||||
(*copy_channel_in)(buf, 1,
|
||||
pcm, st->layout.nb_channels, chan, frame_size);
|
||||
pcm, st->layout.nb_channels, chan, frame_size, user_data);
|
||||
ptr += align(mono_size);
|
||||
if (st->mapping_type == MAPPING_TYPE_SURROUND)
|
||||
{
|
||||
|
@ -1013,6 +975,9 @@ static int opus_multistream_encode_native
|
|||
curr_max = max_data_bytes - tot_size;
|
||||
/* Reserve one byte for the last stream and two for the others */
|
||||
curr_max -= IMAX(0,2*(st->layout.nb_streams-s-1)-1);
|
||||
/* For 100 ms, reserve an extra byte per stream for the ToC */
|
||||
if (Fs/frame_size == 10)
|
||||
curr_max -= st->layout.nb_streams-s-1;
|
||||
curr_max = IMIN(curr_max,MS_FRAME_TMP);
|
||||
/* Repacketizer will add one or two bytes for self-delimited frames */
|
||||
if (s != st->layout.nb_streams-1) curr_max -= curr_max>253 ? 2 : 1;
|
||||
|
@ -1053,11 +1018,13 @@ static void opus_copy_channel_in_float(
|
|||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
const float *float_src;
|
||||
opus_int32 i;
|
||||
(void)user_data;
|
||||
float_src = (const float *)src;
|
||||
for (i=0;i<frame_size;i++)
|
||||
#if defined(FIXED_POINT)
|
||||
|
@ -1074,11 +1041,13 @@ static void opus_copy_channel_in_short(
|
|||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
const opus_int16 *short_src;
|
||||
opus_int32 i;
|
||||
(void)user_data;
|
||||
short_src = (const opus_int16 *)src;
|
||||
for (i=0;i<frame_size;i++)
|
||||
#if defined(FIXED_POINT)
|
||||
|
@ -1099,7 +1068,7 @@ int opus_multistream_encode(
|
|||
)
|
||||
{
|
||||
return opus_multistream_encode_native(st, opus_copy_channel_in_short,
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL);
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
|
@ -1112,7 +1081,7 @@ int opus_multistream_encode_float(
|
|||
)
|
||||
{
|
||||
return opus_multistream_encode_native(st, opus_copy_channel_in_float,
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1);
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_float, 1, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -1128,7 +1097,7 @@ int opus_multistream_encode_float
|
|||
)
|
||||
{
|
||||
return opus_multistream_encode_native(st, opus_copy_channel_in_float,
|
||||
pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1);
|
||||
pcm, frame_size, data, max_data_bytes, 24, downmix_float, 1, NULL);
|
||||
}
|
||||
|
||||
int opus_multistream_encode(
|
||||
|
@ -1140,19 +1109,17 @@ int opus_multistream_encode(
|
|||
)
|
||||
{
|
||||
return opus_multistream_encode_native(st, opus_copy_channel_in_short,
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0);
|
||||
pcm, frame_size, data, max_data_bytes, 16, downmix_int, 0, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
||||
int opus_multistream_encoder_ctl_va_list(OpusMSEncoder *st, int request,
|
||||
va_list ap)
|
||||
{
|
||||
va_list ap;
|
||||
int coupled_size, mono_size;
|
||||
char *ptr;
|
||||
int ret = OPUS_OK;
|
||||
|
||||
va_start(ap, request);
|
||||
|
||||
coupled_size = opus_encoder_get_size(2);
|
||||
mono_size = opus_encoder_get_size(1);
|
||||
ptr = (char*)st + align(sizeof(OpusMSEncoder));
|
||||
|
@ -1161,9 +1128,11 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
case OPUS_SET_BITRATE_REQUEST:
|
||||
{
|
||||
opus_int32 value = va_arg(ap, opus_int32);
|
||||
if (value<0 && value!=OPUS_AUTO && value!=OPUS_BITRATE_MAX)
|
||||
if (value != OPUS_AUTO && value != OPUS_BITRATE_MAX)
|
||||
{
|
||||
goto bad_arg;
|
||||
if (value <= 0)
|
||||
goto bad_arg;
|
||||
value = IMIN(300000*st->layout.nb_channels, IMAX(500*st->layout.nb_channels, value));
|
||||
}
|
||||
st->bitrate_bps = value;
|
||||
}
|
||||
|
@ -1206,6 +1175,7 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
case OPUS_GET_INBAND_FEC_REQUEST:
|
||||
case OPUS_GET_FORCE_CHANNELS_REQUEST:
|
||||
case OPUS_GET_PREDICTION_DISABLED_REQUEST:
|
||||
case OPUS_GET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
OpusEncoder *enc;
|
||||
/* For int32* GET params, just query the first stream */
|
||||
|
@ -1252,6 +1222,7 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
case OPUS_SET_FORCE_MODE_REQUEST:
|
||||
case OPUS_SET_FORCE_CHANNELS_REQUEST:
|
||||
case OPUS_SET_PREDICTION_DISABLED_REQUEST:
|
||||
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
|
||||
{
|
||||
int s;
|
||||
/* This works for int32 params */
|
||||
|
@ -1278,7 +1249,7 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
OpusEncoder **value;
|
||||
stream_id = va_arg(ap, opus_int32);
|
||||
if (stream_id<0 || stream_id >= st->layout.nb_streams)
|
||||
ret = OPUS_BAD_ARG;
|
||||
goto bad_arg;
|
||||
value = va_arg(ap, OpusEncoder**);
|
||||
if (!value)
|
||||
{
|
||||
|
@ -1313,7 +1284,6 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
case OPUS_RESET_STATE:
|
||||
{
|
||||
int s;
|
||||
st->subframe_mem[0] = st->subframe_mem[1] = st->subframe_mem[2] = 0;
|
||||
if (st->mapping_type == MAPPING_TYPE_SURROUND)
|
||||
{
|
||||
OPUS_CLEAR(ms_get_preemph_mem(st), st->layout.nb_channels);
|
||||
|
@ -1337,14 +1307,21 @@ int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
|||
ret = OPUS_UNIMPLEMENTED;
|
||||
break;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
return ret;
|
||||
bad_arg:
|
||||
va_end(ap);
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
int opus_multistream_encoder_ctl(OpusMSEncoder *st, int request, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
va_start(ap, request);
|
||||
ret = opus_multistream_encoder_ctl_va_list(st, request, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void opus_multistream_encoder_destroy(OpusMSEncoder *st)
|
||||
{
|
||||
opus_free(st);
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "opus.h"
|
||||
#include "celt.h"
|
||||
|
||||
#include <stdarg.h> /* va_list */
|
||||
#include <stddef.h> /* offsetof */
|
||||
|
||||
struct OpusRepacketizer {
|
||||
|
@ -50,12 +51,59 @@ typedef struct ChannelLayout {
|
|||
unsigned char mapping[256];
|
||||
} ChannelLayout;
|
||||
|
||||
typedef enum {
|
||||
MAPPING_TYPE_NONE,
|
||||
MAPPING_TYPE_SURROUND,
|
||||
MAPPING_TYPE_AMBISONICS
|
||||
} MappingType;
|
||||
|
||||
struct OpusMSEncoder {
|
||||
ChannelLayout layout;
|
||||
int arch;
|
||||
int lfe_stream;
|
||||
int application;
|
||||
int variable_duration;
|
||||
MappingType mapping_type;
|
||||
opus_int32 bitrate_bps;
|
||||
/* Encoder states go here */
|
||||
/* then opus_val32 window_mem[channels*120]; */
|
||||
/* then opus_val32 preemph_mem[channels]; */
|
||||
};
|
||||
|
||||
struct OpusMSDecoder {
|
||||
ChannelLayout layout;
|
||||
/* Decoder states go here */
|
||||
};
|
||||
|
||||
int opus_multistream_encoder_ctl_va_list(struct OpusMSEncoder *st, int request,
|
||||
va_list ap);
|
||||
int opus_multistream_decoder_ctl_va_list(struct OpusMSDecoder *st, int request,
|
||||
va_list ap);
|
||||
|
||||
int validate_layout(const ChannelLayout *layout);
|
||||
int get_left_channel(const ChannelLayout *layout, int stream_id, int prev);
|
||||
int get_right_channel(const ChannelLayout *layout, int stream_id, int prev);
|
||||
int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev);
|
||||
|
||||
typedef void (*opus_copy_channel_in_func)(
|
||||
opus_val16 *dst,
|
||||
int dst_stride,
|
||||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size,
|
||||
void *user_data
|
||||
);
|
||||
|
||||
typedef void (*opus_copy_channel_out_func)(
|
||||
void *dst,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size,
|
||||
void *user_data
|
||||
);
|
||||
|
||||
#define MODE_SILK_ONLY 1000
|
||||
#define MODE_HYBRID 1001
|
||||
|
@ -87,19 +135,12 @@ int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev);
|
|||
typedef void (*downmix_func)(const void *, opus_val32 *, int, int, int, int, int);
|
||||
void downmix_float(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
|
||||
void downmix_int(const void *_x, opus_val32 *sub, int subframe, int offset, int c1, int c2, int C);
|
||||
int is_digital_silence(const opus_val16* pcm, int frame_size, int channels, int lsb_depth);
|
||||
|
||||
int encode_size(int size, unsigned char *data);
|
||||
|
||||
opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs);
|
||||
|
||||
opus_int32 compute_frame_size(const void *analysis_pcm, int frame_size,
|
||||
int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
|
||||
int delay_compensation, downmix_func downmix
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
, float *subframe_mem
|
||||
#endif
|
||||
);
|
||||
|
||||
opus_int32 opus_encode_native(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
|
||||
unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
|
||||
const void *analysis_pcm, opus_int32 analysis_size, int c1, int c2,
|
||||
|
@ -131,4 +172,30 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int
|
|||
|
||||
int pad_frame(unsigned char *data, opus_int32 len, opus_int32 new_len);
|
||||
|
||||
int opus_multistream_encode_native
|
||||
(
|
||||
struct OpusMSEncoder *st,
|
||||
opus_copy_channel_in_func copy_channel_in,
|
||||
const void *pcm,
|
||||
int analysis_frame_size,
|
||||
unsigned char *data,
|
||||
opus_int32 max_data_bytes,
|
||||
int lsb_depth,
|
||||
downmix_func downmix,
|
||||
int float_api,
|
||||
void *user_data
|
||||
);
|
||||
|
||||
int opus_multistream_decode_native(
|
||||
struct OpusMSDecoder *st,
|
||||
const unsigned char *data,
|
||||
opus_int32 len,
|
||||
void *pcm,
|
||||
opus_copy_channel_out_func copy_channel_out,
|
||||
int frame_size,
|
||||
int decode_fec,
|
||||
int soft_clip,
|
||||
void *user_data
|
||||
);
|
||||
|
||||
#endif /* OPUS_PRIVATE_H */
|
||||
|
|
|
@ -0,0 +1,258 @@
|
|||
/* Copyright (c) 2017 Google Inc.
|
||||
Written by Andrew Allen */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mathops.h"
|
||||
#include "os_support.h"
|
||||
#include "opus_private.h"
|
||||
#include "opus_defines.h"
|
||||
#include "opus_projection.h"
|
||||
#include "opus_multistream.h"
|
||||
#include "mapping_matrix.h"
|
||||
#include "stack_alloc.h"
|
||||
|
||||
struct OpusProjectionDecoder
|
||||
{
|
||||
opus_int32 demixing_matrix_size_in_bytes;
|
||||
/* Encoder states go here */
|
||||
};
|
||||
|
||||
#if !defined(DISABLE_FLOAT_API)
|
||||
static void opus_projection_copy_channel_out_float(
|
||||
void *dst,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size,
|
||||
void *user_data)
|
||||
{
|
||||
float *float_dst;
|
||||
const MappingMatrix *matrix;
|
||||
float_dst = (float *)dst;
|
||||
matrix = (const MappingMatrix *)user_data;
|
||||
|
||||
if (dst_channel == 0)
|
||||
OPUS_CLEAR(float_dst, frame_size * dst_stride);
|
||||
|
||||
if (src != NULL)
|
||||
mapping_matrix_multiply_channel_out_float(matrix, src, dst_channel,
|
||||
src_stride, float_dst, dst_stride, frame_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void opus_projection_copy_channel_out_short(
|
||||
void *dst,
|
||||
int dst_stride,
|
||||
int dst_channel,
|
||||
const opus_val16 *src,
|
||||
int src_stride,
|
||||
int frame_size,
|
||||
void *user_data)
|
||||
{
|
||||
opus_int16 *short_dst;
|
||||
const MappingMatrix *matrix;
|
||||
short_dst = (opus_int16 *)dst;
|
||||
matrix = (const MappingMatrix *)user_data;
|
||||
if (dst_channel == 0)
|
||||
OPUS_CLEAR(short_dst, frame_size * dst_stride);
|
||||
|
||||
if (src != NULL)
|
||||
mapping_matrix_multiply_channel_out_short(matrix, src, dst_channel,
|
||||
src_stride, short_dst, dst_stride, frame_size);
|
||||
}
|
||||
|
||||
static MappingMatrix *get_dec_demixing_matrix(OpusProjectionDecoder *st)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (MappingMatrix*)(void*)((char*)st +
|
||||
align(sizeof(OpusProjectionDecoder)));
|
||||
}
|
||||
|
||||
static OpusMSDecoder *get_multistream_decoder(OpusProjectionDecoder *st)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (OpusMSDecoder*)(void*)((char*)st +
|
||||
align(sizeof(OpusProjectionDecoder) +
|
||||
st->demixing_matrix_size_in_bytes));
|
||||
}
|
||||
|
||||
opus_int32 opus_projection_decoder_get_size(int channels, int streams,
|
||||
int coupled_streams)
|
||||
{
|
||||
opus_int32 matrix_size;
|
||||
opus_int32 decoder_size;
|
||||
|
||||
matrix_size =
|
||||
mapping_matrix_get_size(streams + coupled_streams, channels);
|
||||
if (!matrix_size)
|
||||
return 0;
|
||||
|
||||
decoder_size = opus_multistream_decoder_get_size(streams, coupled_streams);
|
||||
if (!decoder_size)
|
||||
return 0;
|
||||
|
||||
return align(sizeof(OpusProjectionDecoder)) + matrix_size + decoder_size;
|
||||
}
|
||||
|
||||
int opus_projection_decoder_init(OpusProjectionDecoder *st, opus_int32 Fs,
|
||||
int channels, int streams, int coupled_streams,
|
||||
unsigned char *demixing_matrix, opus_int32 demixing_matrix_size)
|
||||
{
|
||||
int nb_input_streams;
|
||||
opus_int32 expected_matrix_size;
|
||||
int i, ret;
|
||||
unsigned char mapping[255];
|
||||
VARDECL(opus_int16, buf);
|
||||
ALLOC_STACK;
|
||||
|
||||
/* Verify supplied matrix size. */
|
||||
nb_input_streams = streams + coupled_streams;
|
||||
expected_matrix_size = nb_input_streams * channels * sizeof(opus_int16);
|
||||
if (expected_matrix_size != demixing_matrix_size)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
/* Convert demixing matrix input into internal format. */
|
||||
ALLOC(buf, nb_input_streams * channels, opus_int16);
|
||||
for (i = 0; i < nb_input_streams * channels; i++)
|
||||
{
|
||||
int s = demixing_matrix[2*i + 1] << 8 | demixing_matrix[2*i];
|
||||
s = ((s & 0xFFFF) ^ 0x8000) - 0x8000;
|
||||
buf[i] = (opus_int16)s;
|
||||
}
|
||||
|
||||
/* Assign demixing matrix. */
|
||||
st->demixing_matrix_size_in_bytes =
|
||||
mapping_matrix_get_size(channels, nb_input_streams);
|
||||
if (!st->demixing_matrix_size_in_bytes)
|
||||
{
|
||||
RESTORE_STACK;
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
mapping_matrix_init(get_dec_demixing_matrix(st), channels, nb_input_streams, 0,
|
||||
buf, demixing_matrix_size);
|
||||
|
||||
/* Set trivial mapping so each input channel pairs with a matrix column. */
|
||||
for (i = 0; i < channels; i++)
|
||||
mapping[i] = i;
|
||||
|
||||
ret = opus_multistream_decoder_init(
|
||||
get_multistream_decoder(st), Fs, channels, streams, coupled_streams, mapping);
|
||||
RESTORE_STACK;
|
||||
return ret;
|
||||
}
|
||||
|
||||
OpusProjectionDecoder *opus_projection_decoder_create(
|
||||
opus_int32 Fs, int channels, int streams, int coupled_streams,
|
||||
unsigned char *demixing_matrix, opus_int32 demixing_matrix_size, int *error)
|
||||
{
|
||||
int size;
|
||||
int ret;
|
||||
OpusProjectionDecoder *st;
|
||||
|
||||
/* Allocate space for the projection decoder. */
|
||||
size = opus_projection_decoder_get_size(channels, streams, coupled_streams);
|
||||
if (!size) {
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
st = (OpusProjectionDecoder *)opus_alloc(size);
|
||||
if (!st)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize projection decoder with provided settings. */
|
||||
ret = opus_projection_decoder_init(st, Fs, channels, streams, coupled_streams,
|
||||
demixing_matrix, demixing_matrix_size);
|
||||
if (ret != OPUS_OK)
|
||||
{
|
||||
opus_free(st);
|
||||
st = NULL;
|
||||
}
|
||||
if (error)
|
||||
*error = ret;
|
||||
return st;
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_int16 *pcm, int frame_size,
|
||||
int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
|
||||
pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 0,
|
||||
get_dec_demixing_matrix(st));
|
||||
}
|
||||
#else
|
||||
int opus_projection_decode(OpusProjectionDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, opus_int16 *pcm, int frame_size,
|
||||
int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
|
||||
pcm, opus_projection_copy_channel_out_short, frame_size, decode_fec, 1,
|
||||
get_dec_demixing_matrix(st));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
int opus_projection_decode_float(OpusProjectionDecoder *st, const unsigned char *data,
|
||||
opus_int32 len, float *pcm, int frame_size, int decode_fec)
|
||||
{
|
||||
return opus_multistream_decode_native(get_multistream_decoder(st), data, len,
|
||||
pcm, opus_projection_copy_channel_out_float, frame_size, decode_fec, 0,
|
||||
get_dec_demixing_matrix(st));
|
||||
}
|
||||
#endif
|
||||
|
||||
int opus_projection_decoder_ctl(OpusProjectionDecoder *st, int request, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret = OPUS_OK;
|
||||
|
||||
va_start(ap, request);
|
||||
ret = opus_multistream_decoder_ctl_va_list(get_multistream_decoder(st),
|
||||
request, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void opus_projection_decoder_destroy(OpusProjectionDecoder *st)
|
||||
{
|
||||
opus_free(st);
|
||||
}
|
||||
|
|
@ -0,0 +1,468 @@
|
|||
/* Copyright (c) 2017 Google Inc.
|
||||
Written by Andrew Allen */
|
||||
/*
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "mathops.h"
|
||||
#include "os_support.h"
|
||||
#include "opus_private.h"
|
||||
#include "opus_defines.h"
|
||||
#include "opus_projection.h"
|
||||
#include "opus_multistream.h"
|
||||
#include "stack_alloc.h"
|
||||
#include "mapping_matrix.h"
|
||||
|
||||
struct OpusProjectionEncoder
|
||||
{
|
||||
opus_int32 mixing_matrix_size_in_bytes;
|
||||
opus_int32 demixing_matrix_size_in_bytes;
|
||||
/* Encoder states go here */
|
||||
};
|
||||
|
||||
#if !defined(DISABLE_FLOAT_API)
|
||||
static void opus_projection_copy_channel_in_float(
|
||||
opus_val16 *dst,
|
||||
int dst_stride,
|
||||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
mapping_matrix_multiply_channel_in_float((const MappingMatrix*)user_data,
|
||||
(const float*)src, src_stride, dst, src_channel, dst_stride, frame_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void opus_projection_copy_channel_in_short(
|
||||
opus_val16 *dst,
|
||||
int dst_stride,
|
||||
const void *src,
|
||||
int src_stride,
|
||||
int src_channel,
|
||||
int frame_size,
|
||||
void *user_data
|
||||
)
|
||||
{
|
||||
mapping_matrix_multiply_channel_in_short((const MappingMatrix*)user_data,
|
||||
(const opus_int16*)src, src_stride, dst, src_channel, dst_stride, frame_size);
|
||||
}
|
||||
|
||||
static int get_order_plus_one_from_channels(int channels, int *order_plus_one)
|
||||
{
|
||||
int order_plus_one_;
|
||||
int acn_channels;
|
||||
int nondiegetic_channels;
|
||||
|
||||
/* Allowed numbers of channels:
|
||||
* (1 + n)^2 + 2j, for n = 0...14 and j = 0 or 1.
|
||||
*/
|
||||
if (channels < 1 || channels > 227)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
order_plus_one_ = isqrt32(channels);
|
||||
acn_channels = order_plus_one_ * order_plus_one_;
|
||||
nondiegetic_channels = channels - acn_channels;
|
||||
if (nondiegetic_channels != 0 && nondiegetic_channels != 2)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
if (order_plus_one)
|
||||
*order_plus_one = order_plus_one_;
|
||||
return OPUS_OK;
|
||||
}
|
||||
|
||||
static int get_streams_from_channels(int channels, int mapping_family,
|
||||
int *streams, int *coupled_streams,
|
||||
int *order_plus_one)
|
||||
{
|
||||
if (mapping_family == 3)
|
||||
{
|
||||
if (get_order_plus_one_from_channels(channels, order_plus_one) != OPUS_OK)
|
||||
return OPUS_BAD_ARG;
|
||||
if (streams)
|
||||
*streams = (channels + 1) / 2;
|
||||
if (coupled_streams)
|
||||
*coupled_streams = channels / 2;
|
||||
return OPUS_OK;
|
||||
}
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
static MappingMatrix *get_mixing_matrix(OpusProjectionEncoder *st)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (MappingMatrix *)(void*)((char*)st +
|
||||
align(sizeof(OpusProjectionEncoder)));
|
||||
}
|
||||
|
||||
static MappingMatrix *get_enc_demixing_matrix(OpusProjectionEncoder *st)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (MappingMatrix *)(void*)((char*)st +
|
||||
align(sizeof(OpusProjectionEncoder) +
|
||||
st->mixing_matrix_size_in_bytes));
|
||||
}
|
||||
|
||||
static OpusMSEncoder *get_multistream_encoder(OpusProjectionEncoder *st)
|
||||
{
|
||||
/* void* cast avoids clang -Wcast-align warning */
|
||||
return (OpusMSEncoder *)(void*)((char*)st +
|
||||
align(sizeof(OpusProjectionEncoder) +
|
||||
st->mixing_matrix_size_in_bytes +
|
||||
st->demixing_matrix_size_in_bytes));
|
||||
}
|
||||
|
||||
opus_int32 opus_projection_ambisonics_encoder_get_size(int channels,
|
||||
int mapping_family)
|
||||
{
|
||||
int nb_streams;
|
||||
int nb_coupled_streams;
|
||||
int order_plus_one;
|
||||
int mixing_matrix_rows, mixing_matrix_cols;
|
||||
int demixing_matrix_rows, demixing_matrix_cols;
|
||||
opus_int32 mixing_matrix_size, demixing_matrix_size;
|
||||
opus_int32 encoder_size;
|
||||
int ret;
|
||||
|
||||
ret = get_streams_from_channels(channels, mapping_family, &nb_streams,
|
||||
&nb_coupled_streams, &order_plus_one);
|
||||
if (ret != OPUS_OK)
|
||||
return 0;
|
||||
|
||||
if (order_plus_one == 2)
|
||||
{
|
||||
mixing_matrix_rows = mapping_matrix_foa_mixing.rows;
|
||||
mixing_matrix_cols = mapping_matrix_foa_mixing.cols;
|
||||
demixing_matrix_rows = mapping_matrix_foa_demixing.rows;
|
||||
demixing_matrix_cols = mapping_matrix_foa_demixing.cols;
|
||||
}
|
||||
else if (order_plus_one == 3)
|
||||
{
|
||||
mixing_matrix_rows = mapping_matrix_soa_mixing.rows;
|
||||
mixing_matrix_cols = mapping_matrix_soa_mixing.cols;
|
||||
demixing_matrix_rows = mapping_matrix_soa_demixing.rows;
|
||||
demixing_matrix_cols = mapping_matrix_soa_demixing.cols;
|
||||
}
|
||||
else if (order_plus_one == 4)
|
||||
{
|
||||
mixing_matrix_rows = mapping_matrix_toa_mixing.rows;
|
||||
mixing_matrix_cols = mapping_matrix_toa_mixing.cols;
|
||||
demixing_matrix_rows = mapping_matrix_toa_demixing.rows;
|
||||
demixing_matrix_cols = mapping_matrix_toa_demixing.cols;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
mixing_matrix_size =
|
||||
mapping_matrix_get_size(mixing_matrix_rows, mixing_matrix_cols);
|
||||
if (!mixing_matrix_size)
|
||||
return 0;
|
||||
|
||||
demixing_matrix_size =
|
||||
mapping_matrix_get_size(demixing_matrix_rows, demixing_matrix_cols);
|
||||
if (!demixing_matrix_size)
|
||||
return 0;
|
||||
|
||||
encoder_size =
|
||||
opus_multistream_encoder_get_size(nb_streams, nb_coupled_streams);
|
||||
if (!encoder_size)
|
||||
return 0;
|
||||
|
||||
return align(sizeof(OpusProjectionEncoder)) +
|
||||
mixing_matrix_size + demixing_matrix_size + encoder_size;
|
||||
}
|
||||
|
||||
int opus_projection_ambisonics_encoder_init(OpusProjectionEncoder *st, opus_int32 Fs,
|
||||
int channels, int mapping_family,
|
||||
int *streams, int *coupled_streams,
|
||||
int application)
|
||||
{
|
||||
MappingMatrix *mixing_matrix;
|
||||
MappingMatrix *demixing_matrix;
|
||||
OpusMSEncoder *ms_encoder;
|
||||
int i;
|
||||
int ret;
|
||||
int order_plus_one;
|
||||
unsigned char mapping[255];
|
||||
|
||||
if (streams == NULL || coupled_streams == NULL) {
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
||||
if (get_streams_from_channels(channels, mapping_family, streams,
|
||||
coupled_streams, &order_plus_one) != OPUS_OK)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
if (mapping_family == 3)
|
||||
{
|
||||
/* Assign mixing matrix based on available pre-computed matrices. */
|
||||
mixing_matrix = get_mixing_matrix(st);
|
||||
if (order_plus_one == 2)
|
||||
{
|
||||
mapping_matrix_init(mixing_matrix, mapping_matrix_foa_mixing.rows,
|
||||
mapping_matrix_foa_mixing.cols, mapping_matrix_foa_mixing.gain,
|
||||
mapping_matrix_foa_mixing_data,
|
||||
sizeof(mapping_matrix_foa_mixing_data));
|
||||
}
|
||||
else if (order_plus_one == 3)
|
||||
{
|
||||
mapping_matrix_init(mixing_matrix, mapping_matrix_soa_mixing.rows,
|
||||
mapping_matrix_soa_mixing.cols, mapping_matrix_soa_mixing.gain,
|
||||
mapping_matrix_soa_mixing_data,
|
||||
sizeof(mapping_matrix_soa_mixing_data));
|
||||
}
|
||||
else if (order_plus_one == 4)
|
||||
{
|
||||
mapping_matrix_init(mixing_matrix, mapping_matrix_toa_mixing.rows,
|
||||
mapping_matrix_toa_mixing.cols, mapping_matrix_toa_mixing.gain,
|
||||
mapping_matrix_toa_mixing_data,
|
||||
sizeof(mapping_matrix_toa_mixing_data));
|
||||
}
|
||||
else
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
st->mixing_matrix_size_in_bytes = mapping_matrix_get_size(
|
||||
mixing_matrix->rows, mixing_matrix->cols);
|
||||
if (!st->mixing_matrix_size_in_bytes)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
/* Assign demixing matrix based on available pre-computed matrices. */
|
||||
demixing_matrix = get_enc_demixing_matrix(st);
|
||||
if (order_plus_one == 2)
|
||||
{
|
||||
mapping_matrix_init(demixing_matrix, mapping_matrix_foa_demixing.rows,
|
||||
mapping_matrix_foa_demixing.cols, mapping_matrix_foa_demixing.gain,
|
||||
mapping_matrix_foa_demixing_data,
|
||||
sizeof(mapping_matrix_foa_demixing_data));
|
||||
}
|
||||
else if (order_plus_one == 3)
|
||||
{
|
||||
mapping_matrix_init(demixing_matrix, mapping_matrix_soa_demixing.rows,
|
||||
mapping_matrix_soa_demixing.cols, mapping_matrix_soa_demixing.gain,
|
||||
mapping_matrix_soa_demixing_data,
|
||||
sizeof(mapping_matrix_soa_demixing_data));
|
||||
}
|
||||
else if (order_plus_one == 4)
|
||||
{
|
||||
mapping_matrix_init(demixing_matrix, mapping_matrix_toa_demixing.rows,
|
||||
mapping_matrix_toa_demixing.cols, mapping_matrix_toa_demixing.gain,
|
||||
mapping_matrix_toa_demixing_data,
|
||||
sizeof(mapping_matrix_toa_demixing_data));
|
||||
}
|
||||
else
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
st->demixing_matrix_size_in_bytes = mapping_matrix_get_size(
|
||||
demixing_matrix->rows, demixing_matrix->cols);
|
||||
if (!st->demixing_matrix_size_in_bytes)
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
else
|
||||
return OPUS_UNIMPLEMENTED;
|
||||
|
||||
/* Ensure matrices are large enough for desired coding scheme. */
|
||||
if (*streams + *coupled_streams > mixing_matrix->rows ||
|
||||
channels > mixing_matrix->cols ||
|
||||
channels > demixing_matrix->rows ||
|
||||
*streams + *coupled_streams > demixing_matrix->cols)
|
||||
return OPUS_BAD_ARG;
|
||||
|
||||
/* Set trivial mapping so each input channel pairs with a matrix column. */
|
||||
for (i = 0; i < channels; i++)
|
||||
mapping[i] = i;
|
||||
|
||||
/* Initialize multistream encoder with provided settings. */
|
||||
ms_encoder = get_multistream_encoder(st);
|
||||
ret = opus_multistream_encoder_init(ms_encoder, Fs, channels, *streams,
|
||||
*coupled_streams, mapping, application);
|
||||
return ret;
|
||||
}
|
||||
|
||||
OpusProjectionEncoder *opus_projection_ambisonics_encoder_create(
|
||||
opus_int32 Fs, int channels, int mapping_family, int *streams,
|
||||
int *coupled_streams, int application, int *error)
|
||||
{
|
||||
int size;
|
||||
int ret;
|
||||
OpusProjectionEncoder *st;
|
||||
|
||||
/* Allocate space for the projection encoder. */
|
||||
size = opus_projection_ambisonics_encoder_get_size(channels, mapping_family);
|
||||
if (!size) {
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
st = (OpusProjectionEncoder *)opus_alloc(size);
|
||||
if (!st)
|
||||
{
|
||||
if (error)
|
||||
*error = OPUS_ALLOC_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Initialize projection encoder with provided settings. */
|
||||
ret = opus_projection_ambisonics_encoder_init(st, Fs, channels,
|
||||
mapping_family, streams, coupled_streams, application);
|
||||
if (ret != OPUS_OK)
|
||||
{
|
||||
opus_free(st);
|
||||
st = NULL;
|
||||
}
|
||||
if (error)
|
||||
*error = ret;
|
||||
return st;
|
||||
}
|
||||
|
||||
int opus_projection_encode(OpusProjectionEncoder *st, const opus_int16 *pcm,
|
||||
int frame_size, unsigned char *data,
|
||||
opus_int32 max_data_bytes)
|
||||
{
|
||||
return opus_multistream_encode_native(get_multistream_encoder(st),
|
||||
opus_projection_copy_channel_in_short, pcm, frame_size, data,
|
||||
max_data_bytes, 16, downmix_int, 0, get_mixing_matrix(st));
|
||||
}
|
||||
|
||||
#ifndef DISABLE_FLOAT_API
|
||||
#ifdef FIXED_POINT
|
||||
int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm,
|
||||
int frame_size, unsigned char *data,
|
||||
opus_int32 max_data_bytes)
|
||||
{
|
||||
return opus_multistream_encode_native(get_multistream_encoder(st),
|
||||
opus_projection_copy_channel_in_float, pcm, frame_size, data,
|
||||
max_data_bytes, 16, downmix_float, 1, get_mixing_matrix(st));
|
||||
}
|
||||
#else
|
||||
int opus_projection_encode_float(OpusProjectionEncoder *st, const float *pcm,
|
||||
int frame_size, unsigned char *data,
|
||||
opus_int32 max_data_bytes)
|
||||
{
|
||||
return opus_multistream_encode_native(get_multistream_encoder(st),
|
||||
opus_projection_copy_channel_in_float, pcm, frame_size, data,
|
||||
max_data_bytes, 24, downmix_float, 1, get_mixing_matrix(st));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
void opus_projection_encoder_destroy(OpusProjectionEncoder *st)
|
||||
{
|
||||
opus_free(st);
|
||||
}
|
||||
|
||||
int opus_projection_encoder_ctl(OpusProjectionEncoder *st, int request, ...)
|
||||
{
|
||||
va_list ap;
|
||||
MappingMatrix *demixing_matrix;
|
||||
OpusMSEncoder *ms_encoder;
|
||||
int ret = OPUS_OK;
|
||||
|
||||
ms_encoder = get_multistream_encoder(st);
|
||||
demixing_matrix = get_enc_demixing_matrix(st);
|
||||
|
||||
va_start(ap, request);
|
||||
switch(request)
|
||||
{
|
||||
case OPUS_PROJECTION_GET_DEMIXING_MATRIX_SIZE_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value =
|
||||
ms_encoder->layout.nb_channels * (ms_encoder->layout.nb_streams
|
||||
+ ms_encoder->layout.nb_coupled_streams) * sizeof(opus_int16);
|
||||
}
|
||||
break;
|
||||
case OPUS_PROJECTION_GET_DEMIXING_MATRIX_GAIN_REQUEST:
|
||||
{
|
||||
opus_int32 *value = va_arg(ap, opus_int32*);
|
||||
if (!value)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
*value = demixing_matrix->gain;
|
||||
}
|
||||
break;
|
||||
case OPUS_PROJECTION_GET_DEMIXING_MATRIX_REQUEST:
|
||||
{
|
||||
int i, j, k, l;
|
||||
int nb_input_streams;
|
||||
int nb_output_streams;
|
||||
unsigned char *external_char;
|
||||
opus_int16 *internal_short;
|
||||
opus_int32 external_size;
|
||||
opus_int32 internal_size;
|
||||
|
||||
/* (I/O is in relation to the decoder's perspective). */
|
||||
nb_input_streams = ms_encoder->layout.nb_streams +
|
||||
ms_encoder->layout.nb_coupled_streams;
|
||||
nb_output_streams = ms_encoder->layout.nb_channels;
|
||||
|
||||
external_char = va_arg(ap, unsigned char *);
|
||||
external_size = va_arg(ap, opus_int32);
|
||||
if (!external_char)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
internal_short = mapping_matrix_get_data(demixing_matrix);
|
||||
internal_size = nb_input_streams * nb_output_streams * sizeof(opus_int16);
|
||||
if (external_size != internal_size)
|
||||
{
|
||||
goto bad_arg;
|
||||
}
|
||||
|
||||
/* Copy demixing matrix subset to output destination. */
|
||||
l = 0;
|
||||
for (i = 0; i < nb_input_streams; i++) {
|
||||
for (j = 0; j < nb_output_streams; j++) {
|
||||
k = demixing_matrix->rows * i + j;
|
||||
external_char[2*l] = (unsigned char)internal_short[k];
|
||||
external_char[2*l+1] = (unsigned char)(internal_short[k] >> 8);
|
||||
l++;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
ret = opus_multistream_encoder_ctl_va_list(ms_encoder, request, ap);
|
||||
}
|
||||
break;
|
||||
}
|
||||
va_end(ap);
|
||||
return ret;
|
||||
|
||||
bad_arg:
|
||||
va_end(ap);
|
||||
return OPUS_BAD_ARG;
|
||||
}
|
||||
|
|
@ -86,14 +86,15 @@ int op_test(OpusHead *_head,
|
|||
This is to prevent us spending a lot of time allocating memory and looking
|
||||
for Ogg pages in non-Ogg files.*/
|
||||
if(memcmp(_initial_data,"OggS",4)!=0)return OP_ENOTFORMAT;
|
||||
if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT;
|
||||
ogg_sync_init(&oy);
|
||||
data=ogg_sync_buffer(&oy,_initial_bytes);
|
||||
data=ogg_sync_buffer(&oy,(long)_initial_bytes);
|
||||
if(data!=NULL){
|
||||
ogg_stream_state os;
|
||||
ogg_page og;
|
||||
int ret;
|
||||
memcpy(data,_initial_data,_initial_bytes);
|
||||
ogg_sync_wrote(&oy,_initial_bytes);
|
||||
ogg_sync_wrote(&oy,(long)_initial_bytes);
|
||||
ogg_stream_init(&os,-1);
|
||||
err=OP_FALSE;
|
||||
do{
|
||||
|
@ -147,7 +148,7 @@ static int op_get_data(OggOpusFile *_of,int _nbytes){
|
|||
int nbytes;
|
||||
OP_ASSERT(_nbytes>0);
|
||||
buffer=(unsigned char *)ogg_sync_buffer(&_of->oy,_nbytes);
|
||||
nbytes=(int)(*_of->callbacks.read)(_of->source,buffer,_nbytes);
|
||||
nbytes=(int)(*_of->callbacks.read)(_of->stream,buffer,_nbytes);
|
||||
OP_ASSERT(nbytes<=_nbytes);
|
||||
if(OP_LIKELY(nbytes>0))ogg_sync_wrote(&_of->oy,nbytes);
|
||||
return nbytes;
|
||||
|
@ -157,7 +158,7 @@ static int op_get_data(OggOpusFile *_of,int _nbytes){
|
|||
static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
|
||||
if(_offset==_of->offset)return 0;
|
||||
if(_of->callbacks.seek==NULL
|
||||
||(*_of->callbacks.seek)(_of->source,_offset,SEEK_SET)){
|
||||
||(*_of->callbacks.seek)(_of->stream,_offset,SEEK_SET)){
|
||||
return OP_EREAD;
|
||||
}
|
||||
_of->offset=_offset;
|
||||
|
@ -165,7 +166,7 @@ static int op_seek_helper(OggOpusFile *_of,opus_int64 _offset){
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*Get the current position indicator of the underlying source.
|
||||
/*Get the current position indicator of the underlying stream.
|
||||
This should be the same as the value reported by tell().*/
|
||||
static opus_int64 op_position(const OggOpusFile *_of){
|
||||
/*The current position indicator is _not_ simply offset.
|
||||
|
@ -369,7 +370,7 @@ static int op_get_prev_page_serial(OggOpusFile *_of,OpusSeekRecord *_sr,
|
|||
search_start=llret+1;
|
||||
}
|
||||
/*We started from the beginning of the stream and found nothing.
|
||||
This should be impossible unless the contents of the source changed out
|
||||
This should be impossible unless the contents of the stream changed out
|
||||
from under us after we read from it.*/
|
||||
if(OP_UNLIKELY(!begin)&&OP_UNLIKELY(_offset<0))return OP_EBADLINK;
|
||||
/*Bump up the chunk size.
|
||||
|
@ -455,7 +456,7 @@ static opus_int64 op_get_last_page(OggOpusFile *_of,ogg_int64_t *_gp,
|
|||
}
|
||||
}
|
||||
/*We started from at or before the beginning of the link and found nothing.
|
||||
This should be impossible unless the contents of the source changed out
|
||||
This should be impossible unless the contents of the stream changed out
|
||||
from under us after we read from it.*/
|
||||
if((OP_UNLIKELY(left_link)||OP_UNLIKELY(!begin))&&OP_UNLIKELY(_offset<0)){
|
||||
return OP_EBADLINK;
|
||||
|
@ -855,6 +856,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||
/*Fail if the pre-skip is non-zero, since it's asking us to skip more
|
||||
samples than exist.*/
|
||||
if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
|
||||
_link->pcm_file_offset=0;
|
||||
/*Set pcm_end and end_offset so we can skip the call to
|
||||
op_find_final_pcm_offset().*/
|
||||
_link->pcm_start=_link->pcm_end=0;
|
||||
|
@ -866,7 +868,8 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||
if(_link->head.pre_skip>0)return OP_EBADTIMESTAMP;
|
||||
/*Set pcm_end and end_offset so we can skip the call to
|
||||
op_find_final_pcm_offset().*/
|
||||
_link->pcm_end=_link->pcm_start=0;
|
||||
_link->pcm_file_offset=0;
|
||||
_link->pcm_start=_link->pcm_end=0;
|
||||
_link->end_offset=_link->data_offset;
|
||||
/*Tell the caller we've got a buffered page for them.*/
|
||||
return 1;
|
||||
|
@ -951,6 +954,7 @@ static int op_find_initial_pcm_offset(OggOpusFile *_of,
|
|||
/*Update the packet count after end-trimming.*/
|
||||
_of->op_count=pi;
|
||||
_of->cur_discard_count=_link->head.pre_skip;
|
||||
_link->pcm_file_offset=0;
|
||||
_of->prev_packet_gp=_link->pcm_start=pcm_start;
|
||||
_of->prev_page_offset=page_offset;
|
||||
return 0;
|
||||
|
@ -1271,6 +1275,7 @@ static int op_bisect_forward_serialno(OggOpusFile *_of,
|
|||
always starts with a seek.*/
|
||||
ret=op_find_initial_pcm_offset(_of,links+nlinks,NULL);
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
links[nlinks].pcm_file_offset=total_duration;
|
||||
_searched=_of->offset;
|
||||
/*Mark the current link count so it can be cleaned up on error.*/
|
||||
_of->nlinks=++nlinks;
|
||||
|
@ -1390,8 +1395,8 @@ static int op_open_seekable2_impl(OggOpusFile *_of){
|
|||
opus_int64 data_offset;
|
||||
int ret;
|
||||
/*We can seek, so set out learning all about this file.*/
|
||||
(*_of->callbacks.seek)(_of->source,0,SEEK_END);
|
||||
_of->offset=_of->end=(*_of->callbacks.tell)(_of->source);
|
||||
(*_of->callbacks.seek)(_of->stream,0,SEEK_END);
|
||||
_of->offset=_of->end=(*_of->callbacks.tell)(_of->stream);
|
||||
if(OP_UNLIKELY(_of->end<0))return OP_EREAD;
|
||||
data_offset=_of->links[0].data_offset;
|
||||
if(OP_UNLIKELY(_of->end<data_offset))return OP_EBADLINK;
|
||||
|
@ -1436,7 +1441,7 @@ static int op_open_seekable2(OggOpusFile *_of){
|
|||
prev_page_offset=_of->prev_page_offset;
|
||||
start_offset=_of->offset;
|
||||
memcpy(op_start,_of->op,sizeof(*op_start)*start_op_count);
|
||||
OP_ASSERT((*_of->callbacks.tell)(_of->source)==op_position(_of));
|
||||
OP_ASSERT((*_of->callbacks.tell)(_of->stream)==op_position(_of));
|
||||
ogg_sync_init(&_of->oy);
|
||||
ogg_stream_init(&_of->os,-1);
|
||||
ret=op_open_seekable2_impl(_of);
|
||||
|
@ -1454,7 +1459,7 @@ static int op_open_seekable2(OggOpusFile *_of){
|
|||
_of->cur_discard_count=_of->links[0].head.pre_skip;
|
||||
if(OP_UNLIKELY(ret<0))return ret;
|
||||
/*And restore the position indicator.*/
|
||||
ret=(*_of->callbacks.seek)(_of->source,op_position(_of),SEEK_SET);
|
||||
ret=(*_of->callbacks.seek)(_of->stream,op_position(_of),SEEK_SET);
|
||||
return OP_UNLIKELY(ret<0)?OP_EREAD:0;
|
||||
}
|
||||
|
||||
|
@ -1493,19 +1498,20 @@ static void op_clear(OggOpusFile *_of){
|
|||
_ogg_free(_of->serialnos);
|
||||
ogg_stream_clear(&_of->os);
|
||||
ogg_sync_clear(&_of->oy);
|
||||
if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->source);
|
||||
if(_of->callbacks.close!=NULL)(*_of->callbacks.close)(_of->stream);
|
||||
}
|
||||
|
||||
static int op_open1(OggOpusFile *_of,
|
||||
void *_source,const OpusFileCallbacks *_cb,
|
||||
void *_stream,const OpusFileCallbacks *_cb,
|
||||
const unsigned char *_initial_data,size_t _initial_bytes){
|
||||
ogg_page og;
|
||||
ogg_page *pog;
|
||||
int seekable;
|
||||
int ret;
|
||||
memset(_of,0,sizeof(*_of));
|
||||
if(OP_UNLIKELY(_initial_bytes>(size_t)LONG_MAX))return OP_EFAULT;
|
||||
_of->end=-1;
|
||||
_of->source=_source;
|
||||
_of->stream=_stream;
|
||||
*&_of->callbacks=*_cb;
|
||||
/*At a minimum, we need to be able to read data.*/
|
||||
if(OP_UNLIKELY(_of->callbacks.read==NULL))return OP_EREAD;
|
||||
|
@ -1520,18 +1526,18 @@ static int op_open1(OggOpusFile *_of,
|
|||
decoding entire files from RAM.*/
|
||||
if(_initial_bytes>0){
|
||||
char *buffer;
|
||||
buffer=ogg_sync_buffer(&_of->oy,_initial_bytes);
|
||||
buffer=ogg_sync_buffer(&_of->oy,(long)_initial_bytes);
|
||||
memcpy(buffer,_initial_data,_initial_bytes*sizeof(*buffer));
|
||||
ogg_sync_wrote(&_of->oy,_initial_bytes);
|
||||
ogg_sync_wrote(&_of->oy,(long)_initial_bytes);
|
||||
}
|
||||
/*Can we seek?
|
||||
Stevens suggests the seek test is portable.*/
|
||||
seekable=_cb->seek!=NULL&&(*_cb->seek)(_source,0,SEEK_CUR)!=-1;
|
||||
seekable=_cb->seek!=NULL&&(*_cb->seek)(_stream,0,SEEK_CUR)!=-1;
|
||||
/*If seek is implemented, tell must also be implemented.*/
|
||||
if(seekable){
|
||||
opus_int64 pos;
|
||||
if(OP_UNLIKELY(_of->callbacks.tell==NULL))return OP_EINVAL;
|
||||
pos=(*_of->callbacks.tell)(_of->source);
|
||||
pos=(*_of->callbacks.tell)(_of->stream);
|
||||
/*If the current position is not equal to the initial bytes consumed,
|
||||
absolute seeking will not work.*/
|
||||
if(OP_UNLIKELY(pos!=(opus_int64)_initial_bytes))return OP_EINVAL;
|
||||
|
@ -1590,14 +1596,14 @@ static int op_open2(OggOpusFile *_of){
|
|||
return ret;
|
||||
}
|
||||
|
||||
OggOpusFile *op_test_callbacks(void *_source,const OpusFileCallbacks *_cb,
|
||||
OggOpusFile *op_test_callbacks(void *_stream,const OpusFileCallbacks *_cb,
|
||||
const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
|
||||
OggOpusFile *of;
|
||||
int ret;
|
||||
of=(OggOpusFile *)_ogg_malloc(sizeof(*of));
|
||||
ret=OP_EFAULT;
|
||||
if(OP_LIKELY(of!=NULL)){
|
||||
ret=op_open1(of,_source,_cb,_initial_data,_initial_bytes);
|
||||
ret=op_open1(of,_stream,_cb,_initial_data,_initial_bytes);
|
||||
if(OP_LIKELY(ret>=0)){
|
||||
if(_error!=NULL)*_error=0;
|
||||
return of;
|
||||
|
@ -1611,10 +1617,10 @@ OggOpusFile *op_test_callbacks(void *_source,const OpusFileCallbacks *_cb,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
OggOpusFile *op_open_callbacks(void *_source,const OpusFileCallbacks *_cb,
|
||||
OggOpusFile *op_open_callbacks(void *_stream,const OpusFileCallbacks *_cb,
|
||||
const unsigned char *_initial_data,size_t _initial_bytes,int *_error){
|
||||
OggOpusFile *of;
|
||||
of=op_test_callbacks(_source,_cb,_initial_data,_initial_bytes,_error);
|
||||
of=op_test_callbacks(_stream,_cb,_initial_data,_initial_bytes,_error);
|
||||
if(OP_LIKELY(of!=NULL)){
|
||||
int ret;
|
||||
ret=op_open2(of);
|
||||
|
@ -1627,15 +1633,15 @@ OggOpusFile *op_open_callbacks(void *_source,const OpusFileCallbacks *_cb,
|
|||
|
||||
/*Convenience routine to clean up from failure for the open functions that
|
||||
create their own streams.*/
|
||||
static OggOpusFile *op_open_close_on_failure(void *_source,
|
||||
static OggOpusFile *op_open_close_on_failure(void *_stream,
|
||||
const OpusFileCallbacks *_cb,int *_error){
|
||||
OggOpusFile *of;
|
||||
if(OP_UNLIKELY(_source==NULL)){
|
||||
if(OP_UNLIKELY(_stream==NULL)){
|
||||
if(_error!=NULL)*_error=OP_EFAULT;
|
||||
return NULL;
|
||||
}
|
||||
of=op_open_callbacks(_source,_cb,NULL,0,_error);
|
||||
if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
|
||||
of=op_open_callbacks(_stream,_cb,NULL,0,_error);
|
||||
if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream);
|
||||
return of;
|
||||
}
|
||||
|
||||
|
@ -1653,15 +1659,15 @@ OggOpusFile *op_open_memory(const unsigned char *_data,size_t _size,
|
|||
|
||||
/*Convenience routine to clean up from failure for the open functions that
|
||||
create their own streams.*/
|
||||
static OggOpusFile *op_test_close_on_failure(void *_source,
|
||||
static OggOpusFile *op_test_close_on_failure(void *_stream,
|
||||
const OpusFileCallbacks *_cb,int *_error){
|
||||
OggOpusFile *of;
|
||||
if(OP_UNLIKELY(_source==NULL)){
|
||||
if(OP_UNLIKELY(_stream==NULL)){
|
||||
if(_error!=NULL)*_error=OP_EFAULT;
|
||||
return NULL;
|
||||
}
|
||||
of=op_test_callbacks(_source,_cb,NULL,0,_error);
|
||||
if(OP_UNLIKELY(of==NULL))(*_cb->close)(_source);
|
||||
of=op_test_callbacks(_stream,_cb,NULL,0,_error);
|
||||
if(OP_UNLIKELY(of==NULL))(*_cb->close)(_stream);
|
||||
return of;
|
||||
}
|
||||
|
||||
|
@ -1702,7 +1708,7 @@ int op_link_count(const OggOpusFile *_of){
|
|||
return _of->nlinks;
|
||||
}
|
||||
|
||||
ogg_uint32_t op_serialno(const OggOpusFile *_of,int _li){
|
||||
opus_uint32 op_serialno(const OggOpusFile *_of,int _li){
|
||||
if(OP_UNLIKELY(_li>=_of->nlinks))_li=_of->nlinks-1;
|
||||
if(!_of->seekable)_li=0;
|
||||
return _of->links[_li<0?_of->cur_link:_li].serialno;
|
||||
|
@ -1718,13 +1724,14 @@ opus_int64 op_raw_total(const OggOpusFile *_of,int _li){
|
|||
||OP_UNLIKELY(_li>=_of->nlinks)){
|
||||
return OP_EINVAL;
|
||||
}
|
||||
if(_li<0)return _of->end-_of->links[0].offset;
|
||||
if(_li<0)return _of->end;
|
||||
return (_li+1>=_of->nlinks?_of->end:_of->links[_li+1].offset)
|
||||
-_of->links[_li].offset;
|
||||
-(_li>0?_of->links[_li].offset:0);
|
||||
}
|
||||
|
||||
ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){
|
||||
OggOpusLink *links;
|
||||
ogg_int64_t pcm_total;
|
||||
ogg_int64_t diff;
|
||||
int nlinks;
|
||||
nlinks=_of->nlinks;
|
||||
|
@ -1737,20 +1744,14 @@ ogg_int64_t op_pcm_total(const OggOpusFile *_of,int _li){
|
|||
/*We verify that the granule position differences are larger than the
|
||||
pre-skip and that the total duration does not overflow during link
|
||||
enumeration, so we don't have to check here.*/
|
||||
pcm_total=0;
|
||||
if(_li<0){
|
||||
ogg_int64_t pcm_total;
|
||||
int li;
|
||||
pcm_total=0;
|
||||
for(li=0;li<nlinks;li++){
|
||||
OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
|
||||
links[li].pcm_end,links[li].pcm_start));
|
||||
pcm_total+=diff-links[li].head.pre_skip;
|
||||
}
|
||||
return pcm_total;
|
||||
pcm_total=links[nlinks-1].pcm_file_offset;
|
||||
_li=nlinks-1;
|
||||
}
|
||||
OP_ALWAYS_TRUE(!op_granpos_diff(&diff,
|
||||
links[_li].pcm_end,links[_li].pcm_start));
|
||||
return diff-links[_li].head.pre_skip;
|
||||
return pcm_total+diff-links[_li].head.pre_skip;
|
||||
}
|
||||
|
||||
const OpusHead *op_head(const OggOpusFile *_of,int _li){
|
||||
|
@ -1820,6 +1821,34 @@ opus_int32 op_bitrate_instant(OggOpusFile *_of){
|
|||
return ret;
|
||||
}
|
||||
|
||||
/*Given a serialno, find a link with a corresponding Opus stream, if it exists.
|
||||
Return: The index of the link to which the page belongs, or a negative number
|
||||
if it was not a desired Opus bitstream section.*/
|
||||
static int op_get_link_from_serialno(const OggOpusFile *_of,int _cur_link,
|
||||
opus_int64 _page_offset,ogg_uint32_t _serialno){
|
||||
const OggOpusLink *links;
|
||||
int nlinks;
|
||||
int li_lo;
|
||||
int li_hi;
|
||||
OP_ASSERT(_of->seekable);
|
||||
links=_of->links;
|
||||
nlinks=_of->nlinks;
|
||||
li_lo=0;
|
||||
/*Start off by guessing we're just a multiplexed page in the current link.*/
|
||||
li_hi=_cur_link+1<nlinks&&_page_offset<links[_cur_link+1].offset?
|
||||
_cur_link+1:nlinks;
|
||||
do{
|
||||
if(_page_offset>=links[_cur_link].offset)li_lo=_cur_link;
|
||||
else li_hi=_cur_link;
|
||||
_cur_link=li_lo+(li_hi-li_lo>>1);
|
||||
}
|
||||
while(li_hi-li_lo>1);
|
||||
/*We've identified the link that should contain this page.
|
||||
Make sure it's a page we care about.*/
|
||||
if(links[_cur_link].serialno!=_serialno)return OP_FALSE;
|
||||
return _cur_link;
|
||||
}
|
||||
|
||||
/*Fetch and process a page.
|
||||
This handles the case where we're at a bitstream boundary and dumps the
|
||||
decoding machine.
|
||||
|
@ -1876,19 +1905,28 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||
if(OP_UNLIKELY(_of->ready_state<OP_STREAMSET)){
|
||||
if(seekable){
|
||||
ogg_uint32_t serialno;
|
||||
int nlinks;
|
||||
int li;
|
||||
serialno=ogg_page_serialno(&og);
|
||||
/*Match the serialno to bitstream section.
|
||||
We use this rather than offset positions to avoid problems near
|
||||
logical bitstream boundaries.*/
|
||||
nlinks=_of->nlinks;
|
||||
for(li=0;li<nlinks&&links[li].serialno!=serialno;li++);
|
||||
/*Not a desired Opus bitstream section.
|
||||
Keep trying.*/
|
||||
if(li>=nlinks)continue;
|
||||
/*Match the serialno to bitstream section.*/
|
||||
OP_ASSERT(cur_link>=0&&cur_link<_of->nlinks);
|
||||
if(links[cur_link].serialno!=serialno){
|
||||
/*It wasn't a page from the current link.
|
||||
Is it from the next one?*/
|
||||
if(OP_LIKELY(cur_link+1<_of->nlinks&&links[cur_link+1].serialno==
|
||||
serialno)){
|
||||
cur_link++;
|
||||
}
|
||||
else{
|
||||
int new_link;
|
||||
new_link=
|
||||
op_get_link_from_serialno(_of,cur_link,_page_offset,serialno);
|
||||
/*Not a desired Opus bitstream section.
|
||||
Keep trying.*/
|
||||
if(new_link<0)continue;
|
||||
cur_link=new_link;
|
||||
}
|
||||
}
|
||||
cur_serialno=serialno;
|
||||
_of->cur_link=cur_link=li;
|
||||
_of->cur_link=cur_link;
|
||||
ogg_stream_reset_serialno(&_of->os,serialno);
|
||||
_of->ready_state=OP_STREAMSET;
|
||||
/*If we're at the start of this link, initialize the granule position
|
||||
|
@ -1942,13 +1980,32 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||
opus_int32 total_duration;
|
||||
int durations[255];
|
||||
int op_count;
|
||||
int report_hole;
|
||||
report_hole=0;
|
||||
total_duration=op_collect_audio_packets(_of,durations);
|
||||
if(OP_UNLIKELY(total_duration<0)){
|
||||
/*Drain the packets from the page anyway.*/
|
||||
/*libogg reported a hole (a gap in the page sequence numbers).
|
||||
Drain the packets from the page anyway.
|
||||
If we don't, they'll still be there when we fetch the next page.
|
||||
Then, when we go to pull out packets, we might get more than 255,
|
||||
which would overrun our packet buffer.*/
|
||||
total_duration=op_collect_audio_packets(_of,durations);
|
||||
OP_ASSERT(total_duration>=0);
|
||||
/*Report holes to the caller.*/
|
||||
if(!_ignore_holes)return OP_HOLE;
|
||||
if(!_ignore_holes){
|
||||
/*Report the hole to the caller after we finish timestamping the
|
||||
packets.*/
|
||||
report_hole=1;
|
||||
/*We had lost or damaged pages, so reset our granule position
|
||||
tracking.
|
||||
This makes holes behave the same as a small raw seek.
|
||||
If the next page is the EOS page, we'll discard it (because we
|
||||
can't perform end trimming properly), and we'll always discard at
|
||||
least 80 ms of audio (to allow decoder state to re-converge).
|
||||
We could try to fill in the gap with PLC by looking at timestamps
|
||||
in the non-EOS case, but that's complicated and error prone and we
|
||||
can't rely on the timestamps being valid.*/
|
||||
_of->prev_packet_gp=-1;
|
||||
}
|
||||
}
|
||||
op_count=_of->op_count;
|
||||
/*If we found at least one audio data packet, compute per-packet granule
|
||||
|
@ -1975,6 +2032,7 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||
Proceed to the next link, rather than risk playing back some
|
||||
samples that shouldn't have been played.*/
|
||||
_of->op_count=0;
|
||||
if(report_hole)return OP_HOLE;
|
||||
continue;
|
||||
}
|
||||
/*By default discard 80 ms of data after a seek, unless we seek
|
||||
|
@ -2020,7 +2078,11 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||
&&OP_LIKELY(diff<total_duration)){
|
||||
cur_packet_gp=prev_packet_gp;
|
||||
for(pi=0;pi<op_count;pi++){
|
||||
diff=durations[pi]-diff;
|
||||
/*Check for overflow.*/
|
||||
if(diff<0&&OP_UNLIKELY(OP_INT64_MAX+diff<durations[pi])){
|
||||
diff=durations[pi]+1;
|
||||
}
|
||||
else diff=durations[pi]-diff;
|
||||
/*If we have samples to trim...*/
|
||||
if(diff>0){
|
||||
/*If we trimmed the entire packet, stop (the spec says encoders
|
||||
|
@ -2076,10 +2138,11 @@ static int op_fetch_and_process_page(OggOpusFile *_of,
|
|||
}
|
||||
_of->prev_packet_gp=prev_packet_gp;
|
||||
_of->prev_page_offset=_page_offset;
|
||||
_of->op_count=pi;
|
||||
/*If end-trimming didn't trim all the packets, we're done.*/
|
||||
if(OP_LIKELY(pi>0))return 0;
|
||||
_of->op_count=op_count=pi;
|
||||
}
|
||||
if(report_hole)return OP_HOLE;
|
||||
/*If end-trimming didn't trim all the packets, we're done.*/
|
||||
if(op_count>0)return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2117,35 +2180,41 @@ static ogg_int64_t op_get_granulepos(const OggOpusFile *_of,
|
|||
ogg_int64_t _pcm_offset,int *_li){
|
||||
const OggOpusLink *links;
|
||||
ogg_int64_t duration;
|
||||
ogg_int64_t pcm_start;
|
||||
opus_int32 pre_skip;
|
||||
int nlinks;
|
||||
int li;
|
||||
int li_lo;
|
||||
int li_hi;
|
||||
OP_ASSERT(_pcm_offset>=0);
|
||||
nlinks=_of->nlinks;
|
||||
links=_of->links;
|
||||
for(li=0;OP_LIKELY(li<nlinks);li++){
|
||||
ogg_int64_t pcm_start;
|
||||
opus_int32 pre_skip;
|
||||
pcm_start=links[li].pcm_start;
|
||||
pre_skip=links[li].head.pre_skip;
|
||||
OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li].pcm_end,pcm_start));
|
||||
duration-=pre_skip;
|
||||
if(_pcm_offset<duration){
|
||||
_pcm_offset+=pre_skip;
|
||||
if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){
|
||||
/*Adding this amount to the granule position would overflow the positive
|
||||
half of its 64-bit range.
|
||||
Since signed overflow is undefined in C, do it in a way the compiler
|
||||
isn't allowed to screw up.*/
|
||||
_pcm_offset-=OP_INT64_MAX-pcm_start+1;
|
||||
pcm_start=OP_INT64_MIN;
|
||||
}
|
||||
pcm_start+=_pcm_offset;
|
||||
*_li=li;
|
||||
return pcm_start;
|
||||
}
|
||||
_pcm_offset-=duration;
|
||||
li_lo=0;
|
||||
li_hi=nlinks;
|
||||
do{
|
||||
int li;
|
||||
li=li_lo+(li_hi-li_lo>>1);
|
||||
if(links[li].pcm_file_offset<=_pcm_offset)li_lo=li;
|
||||
else li_hi=li;
|
||||
}
|
||||
return -1;
|
||||
while(li_hi-li_lo>1);
|
||||
_pcm_offset-=links[li_lo].pcm_file_offset;
|
||||
pcm_start=links[li_lo].pcm_start;
|
||||
pre_skip=links[li_lo].head.pre_skip;
|
||||
OP_ALWAYS_TRUE(!op_granpos_diff(&duration,links[li_lo].pcm_end,pcm_start));
|
||||
duration-=pre_skip;
|
||||
if(_pcm_offset>=duration)return -1;
|
||||
_pcm_offset+=pre_skip;
|
||||
if(OP_UNLIKELY(pcm_start>OP_INT64_MAX-_pcm_offset)){
|
||||
/*Adding this amount to the granule position would overflow the positive
|
||||
half of its 64-bit range.
|
||||
Since signed overflow is undefined in C, do it in a way the compiler
|
||||
isn't allowed to screw up.*/
|
||||
_pcm_offset-=OP_INT64_MAX-pcm_start+1;
|
||||
pcm_start=OP_INT64_MIN;
|
||||
}
|
||||
pcm_start+=_pcm_offset;
|
||||
*_li=li_lo;
|
||||
return pcm_start;
|
||||
}
|
||||
|
||||
/*A small helper to determine if an Ogg page contains data that continues onto
|
||||
|
@ -2532,15 +2601,14 @@ int op_pcm_seek(OggOpusFile *_of,ogg_int64_t _pcm_offset){
|
|||
ogg_int64_t gp;
|
||||
gp=_of->prev_packet_gp;
|
||||
if(OP_LIKELY(gp!=-1)){
|
||||
int nbuffered;
|
||||
ogg_int64_t discard_count;
|
||||
int nbuffered;
|
||||
nbuffered=OP_MAX(_of->od_buffer_size-_of->od_buffer_pos,0);
|
||||
OP_ALWAYS_TRUE(!op_granpos_add(&gp,gp,-nbuffered));
|
||||
/*We do _not_ add cur_discard_count to gp.
|
||||
Otherwise the total amount to discard could grow without bound, and it
|
||||
would be better just to do a full seek.*/
|
||||
if(OP_LIKELY(!op_granpos_diff(&diff,gp,pcm_start))){
|
||||
ogg_int64_t discard_count;
|
||||
discard_count=_pcm_offset-diff;
|
||||
if(OP_LIKELY(!op_granpos_diff(&discard_count,target_gp,gp))){
|
||||
/*We use a threshold of 90 ms instead of 80, since 80 ms is the
|
||||
_minimum_ we would have discarded after a full seek.
|
||||
Assuming 20 ms frames (the default), we'd discard 90 ms on average.*/
|
||||
|
@ -2606,22 +2674,14 @@ static ogg_int64_t op_get_pcm_offset(const OggOpusFile *_of,
|
|||
ogg_int64_t _gp,int _li){
|
||||
const OggOpusLink *links;
|
||||
ogg_int64_t pcm_offset;
|
||||
ogg_int64_t delta;
|
||||
int li;
|
||||
links=_of->links;
|
||||
pcm_offset=0;
|
||||
OP_ASSERT(_li<_of->nlinks);
|
||||
for(li=0;li<_li;li++){
|
||||
OP_ALWAYS_TRUE(!op_granpos_diff(&delta,
|
||||
links[li].pcm_end,links[li].pcm_start));
|
||||
delta-=links[li].head.pre_skip;
|
||||
pcm_offset+=delta;
|
||||
}
|
||||
OP_ASSERT(_li>=0);
|
||||
OP_ASSERT(_li>=0&&_li<_of->nlinks);
|
||||
pcm_offset=links[_li].pcm_file_offset;
|
||||
if(_of->seekable&&OP_UNLIKELY(op_granpos_cmp(_gp,links[_li].pcm_end)>0)){
|
||||
_gp=links[_li].pcm_end;
|
||||
}
|
||||
if(OP_LIKELY(op_granpos_cmp(_gp,links[_li].pcm_start)>0)){
|
||||
ogg_int64_t delta;
|
||||
if(OP_UNLIKELY(op_granpos_diff(&delta,_gp,links[_li].pcm_start)<0)){
|
||||
/*This means an unseekable stream claimed to have a page from more than
|
||||
2 billion days after we joined.*/
|
||||
|
|
|
@ -213,7 +213,8 @@ opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int
|
|||
{
|
||||
/* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
|
||||
padding from opus_packet_pad or opus_packet_unpad(). */
|
||||
celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]);
|
||||
/* assert disabled because it's not valid in C. */
|
||||
/* celt_assert(frames[i] + len[i] <= data || ptr <= frames[i]); */
|
||||
OPUS_MOVE(ptr, frames[i], len[i]);
|
||||
ptr += len[i];
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/* Number of binary divisions, when not in low complexity mode */
|
||||
#define BIN_DIV_STEPS_A2NLSF_FIX 3 /* must be no higher than 16 - log2( LSF_COS_TAB_SZ_FIX ) */
|
||||
#define MAX_ITERATIONS_A2NLSF_FIX 30
|
||||
#define MAX_ITERATIONS_A2NLSF_FIX 16
|
||||
|
||||
/* Helper function for A2NLSF(..) */
|
||||
/* Transforms polynomials from cos(n*f) to cos(f)^n */
|
||||
|
@ -130,7 +130,7 @@ void silk_A2NLSF(
|
|||
const opus_int d /* I Filter order (must be even) */
|
||||
)
|
||||
{
|
||||
opus_int i, k, m, dd, root_ix, ffrac;
|
||||
opus_int i, k, m, dd, root_ix, ffrac;
|
||||
opus_int32 xlo, xhi, xmid;
|
||||
opus_int32 ylo, yhi, ymid, thr;
|
||||
opus_int32 nom, den;
|
||||
|
@ -239,13 +239,13 @@ void silk_A2NLSF(
|
|||
/* Set NLSFs to white spectrum and exit */
|
||||
NLSF[ 0 ] = (opus_int16)silk_DIV32_16( 1 << 15, d + 1 );
|
||||
for( k = 1; k < d; k++ ) {
|
||||
NLSF[ k ] = (opus_int16)silk_SMULBB( k + 1, NLSF[ 0 ] );
|
||||
NLSF[ k ] = (opus_int16)silk_ADD16( NLSF[ k-1 ], NLSF[ 0 ] );
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Error: Apply progressively more bandwidth expansion and run again */
|
||||
silk_bwexpander_32( a_Q16, d, 65536 - silk_SMULBB( 10 + i, i ) ); /* 10_Q16 = 0.00015*/
|
||||
silk_bwexpander_32( a_Q16, d, 65536 - silk_LSHIFT( 1, i ) );
|
||||
|
||||
silk_A2NLSF_init( a_Q16, P, Q, dd );
|
||||
p = P; /* Pointer to polynomial */
|
||||
|
|
|
@ -80,7 +80,8 @@ opus_int silk_Encode( /* O Returns error co
|
|||
opus_int nSamplesIn, /* I Number of samples in input vector */
|
||||
ec_enc *psRangeEnc, /* I/O Compressor data structure */
|
||||
opus_int32 *nBytesOut, /* I/O Number of bytes in payload (input: Max bytes) */
|
||||
const opus_int prefillFlag /* I Flag to indicate prefilling buffers no coding */
|
||||
const opus_int prefillFlag, /* I Flag to indicate prefilling buffers no coding */
|
||||
int activity /* I Decision of Opus voice activity detector */
|
||||
);
|
||||
|
||||
/****************************************/
|
||||
|
|
|
@ -142,12 +142,12 @@ void silk_CNG(
|
|||
silk_CNG_exc( CNG_sig_Q14 + MAX_LPC_ORDER, psCNG->CNG_exc_buf_Q14, length, &psCNG->rand_seed );
|
||||
|
||||
/* Convert CNG NLSF to filter representation */
|
||||
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order );
|
||||
silk_NLSF2A( A_Q12, psCNG->CNG_smth_NLSF_Q15, psDec->LPC_order, psDec->arch );
|
||||
|
||||
/* Generate CNG signal, by synthesis filtering */
|
||||
silk_memcpy( CNG_sig_Q14, psCNG->CNG_synth_state, MAX_LPC_ORDER * sizeof( opus_int32 ) );
|
||||
celt_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
|
||||
for( i = 0; i < length; i++ ) {
|
||||
silk_assert( psDec->LPC_order == 10 || psDec->LPC_order == 16 );
|
||||
/* Avoids introducing a bias because silk_SMLAWB() always rounds to -inf */
|
||||
LPC_pred_Q10 = silk_RSHIFT( psDec->LPC_order, 1 );
|
||||
LPC_pred_Q10 = silk_SMLAWB( LPC_pred_Q10, CNG_sig_Q14[ MAX_LPC_ORDER + i - 1 ], A_Q12[ 0 ] );
|
||||
|
@ -170,7 +170,7 @@ void silk_CNG(
|
|||
}
|
||||
|
||||
/* Update states */
|
||||
CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_LSHIFT( CNG_sig_Q14[ MAX_LPC_ORDER + i ], LPC_pred_Q10, 4 );
|
||||
CNG_sig_Q14[ MAX_LPC_ORDER + i ] = silk_ADD_SAT32( CNG_sig_Q14[ MAX_LPC_ORDER + i ], silk_LSHIFT_SAT32( LPC_pred_Q10, 4 ) );
|
||||
|
||||
/* Scale with Gain and add to input signal */
|
||||
frame[ i ] = (opus_int16)silk_ADD_SAT16( frame[ i ], silk_SAT16( silk_RSHIFT_ROUND( silk_SMULWW( CNG_sig_Q14[ MAX_LPC_ORDER + i ], gain_Q10 ), 8 ) ) );
|
||||
|
|
|
@ -39,6 +39,13 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
/* first d output samples are set to zero */
|
||||
/*******************************************/
|
||||
|
||||
/* OPT: Using celt_fir() for this function should be faster, but it may cause
|
||||
integer overflows in intermediate values (not final results), which the
|
||||
current implementation silences by casting to unsigned. Enabling
|
||||
this should be safe in pretty much all cases, even though it is not technically
|
||||
C89-compliant. */
|
||||
#define USE_CELT_FIR 0
|
||||
|
||||
void silk_LPC_analysis_filter(
|
||||
opus_int16 *out, /* O Output signal */
|
||||
const opus_int16 *in, /* I Input signal */
|
||||
|
@ -49,8 +56,7 @@ void silk_LPC_analysis_filter(
|
|||
)
|
||||
{
|
||||
opus_int j;
|
||||
#ifdef FIXED_POINT
|
||||
opus_int16 mem[SILK_MAX_ORDER_LPC];
|
||||
#if defined(FIXED_POINT) && USE_CELT_FIR
|
||||
opus_int16 num[SILK_MAX_ORDER_LPC];
|
||||
#else
|
||||
int ix;
|
||||
|
@ -58,19 +64,16 @@ void silk_LPC_analysis_filter(
|
|||
const opus_int16 *in_ptr;
|
||||
#endif
|
||||
|
||||
silk_assert( d >= 6 );
|
||||
silk_assert( (d & 1) == 0 );
|
||||
silk_assert( d <= len );
|
||||
celt_assert( d >= 6 );
|
||||
celt_assert( (d & 1) == 0 );
|
||||
celt_assert( d <= len );
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
silk_assert( d <= SILK_MAX_ORDER_LPC );
|
||||
#if defined(FIXED_POINT) && USE_CELT_FIR
|
||||
celt_assert( d <= SILK_MAX_ORDER_LPC );
|
||||
for ( j = 0; j < d; j++ ) {
|
||||
num[ j ] = -B[ j ];
|
||||
}
|
||||
for (j=0;j<d;j++) {
|
||||
mem[ j ] = in[ d - j - 1 ];
|
||||
}
|
||||
celt_fir( in + d, num, out + d, len - d, d, mem, arch );
|
||||
celt_fir( in + d, num, out + d, len - d, d, arch );
|
||||
for ( j = 0; j < d; j++ ) {
|
||||
out[ j ] = 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
/***********************************************************************
|
||||
Copyright (c) 2013, Koen Vos. All rights reserved.
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
- Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
- Neither the name of Internet Society, IETF or IETF Trust, nor the
|
||||
names of specific contributors, may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
***********************************************************************/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "SigProc_FIX.h"
|
||||
|
||||
/* Convert int32 coefficients to int16 coefs and make sure there's no wrap-around */
|
||||
void silk_LPC_fit(
|
||||
opus_int16 *a_QOUT, /* O Output signal */
|
||||
opus_int32 *a_QIN, /* I/O Input signal */
|
||||
const opus_int QOUT, /* I Input Q domain */
|
||||
const opus_int QIN, /* I Input Q domain */
|
||||
const opus_int d /* I Filter order */
|
||||
)
|
||||
{
|
||||
opus_int i, k, idx = 0;
|
||||
opus_int32 maxabs, absval, chirp_Q16;
|
||||
|
||||
/* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
|
||||
for( i = 0; i < 10; i++ ) {
|
||||
/* Find maximum absolute value and its index */
|
||||
maxabs = 0;
|
||||
for( k = 0; k < d; k++ ) {
|
||||
absval = silk_abs( a_QIN[k] );
|
||||
if( absval > maxabs ) {
|
||||
maxabs = absval;
|
||||
idx = k;
|
||||
}
|
||||
}
|
||||
maxabs = silk_RSHIFT_ROUND( maxabs, QIN - QOUT );
|
||||
|
||||
if( maxabs > silk_int16_MAX ) {
|
||||
/* Reduce magnitude of prediction coefficients */
|
||||
maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
|
||||
chirp_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
|
||||
silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
|
||||
silk_bwexpander_32( a_QIN, d, chirp_Q16 );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i == 10 ) {
|
||||
/* Reached the last iteration, clip the coefficients */
|
||||
for( k = 0; k < d; k++ ) {
|
||||
a_QOUT[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT ) );
|
||||
a_QIN[ k ] = silk_LSHIFT( (opus_int32)a_QOUT[ k ], QIN - QOUT );
|
||||
}
|
||||
} else {
|
||||
for( k = 0; k < d; k++ ) {
|
||||
a_QOUT[ k ] = (opus_int16)silk_RSHIFT_ROUND( a_QIN[ k ], QIN - QOUT );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,6 +30,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#endif
|
||||
|
||||
#include "SigProc_FIX.h"
|
||||
#include "define.h"
|
||||
|
||||
#define QA 24
|
||||
#define A_LIMIT SILK_FIX_CONST( 0.99975, QA )
|
||||
|
@ -38,117 +39,103 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
/* Compute inverse of LPC prediction gain, and */
|
||||
/* test if LPC coefficients are stable (all poles within unit circle) */
|
||||
static opus_int32 LPC_inverse_pred_gain_QA( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
opus_int32 A_QA[ 2 ][ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
|
||||
static opus_int32 LPC_inverse_pred_gain_QA_c( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
opus_int32 A_QA[ SILK_MAX_ORDER_LPC ], /* I Prediction coefficients */
|
||||
const opus_int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
opus_int k, n, mult2Q;
|
||||
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp_QA;
|
||||
opus_int32 *Aold_QA, *Anew_QA;
|
||||
opus_int32 invGain_Q30, rc_Q31, rc_mult1_Q30, rc_mult2, tmp1, tmp2;
|
||||
|
||||
Anew_QA = A_QA[ order & 1 ];
|
||||
|
||||
invGain_Q30 = (opus_int32)1 << 30;
|
||||
invGain_Q30 = SILK_FIX_CONST( 1, 30 );
|
||||
for( k = order - 1; k > 0; k-- ) {
|
||||
/* Check for stability */
|
||||
if( ( Anew_QA[ k ] > A_LIMIT ) || ( Anew_QA[ k ] < -A_LIMIT ) ) {
|
||||
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = -silk_LSHIFT( Anew_QA[ k ], 31 - QA );
|
||||
rc_Q31 = -silk_LSHIFT( A_QA[ k ], 31 - QA );
|
||||
|
||||
/* rc_mult1_Q30 range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
|
||||
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
|
||||
silk_assert( rc_mult1_Q30 > ( 1 << 15 ) ); /* reduce A_LIMIT if fails */
|
||||
silk_assert( rc_mult1_Q30 <= ( 1 << 30 ) );
|
||||
|
||||
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
|
||||
mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
|
||||
rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
|
||||
|
||||
/* Update inverse gain */
|
||||
/* invGain_Q30 range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
|
||||
silk_assert( invGain_Q30 >= 0 );
|
||||
silk_assert( invGain_Q30 <= ( 1 << 30 ) );
|
||||
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Swap pointers */
|
||||
Aold_QA = Anew_QA;
|
||||
Anew_QA = A_QA[ k & 1 ];
|
||||
/* rc_mult2 range: [ 2^30 : silk_int32_MAX ] */
|
||||
mult2Q = 32 - silk_CLZ32( silk_abs( rc_mult1_Q30 ) );
|
||||
rc_mult2 = silk_INVERSE32_varQ( rc_mult1_Q30, mult2Q + 30 );
|
||||
|
||||
/* Update AR coefficient */
|
||||
for( n = 0; n < k; n++ ) {
|
||||
tmp_QA = Aold_QA[ n ] - MUL32_FRAC_Q( Aold_QA[ k - n - 1 ], rc_Q31, 31 );
|
||||
Anew_QA[ n ] = MUL32_FRAC_Q( tmp_QA, rc_mult2 , mult2Q );
|
||||
for( n = 0; n < (k + 1) >> 1; n++ ) {
|
||||
opus_int64 tmp64;
|
||||
tmp1 = A_QA[ n ];
|
||||
tmp2 = A_QA[ k - n - 1 ];
|
||||
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp1,
|
||||
MUL32_FRAC_Q( tmp2, rc_Q31, 31 ) ), rc_mult2 ), mult2Q);
|
||||
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
|
||||
return 0;
|
||||
}
|
||||
A_QA[ n ] = ( opus_int32 )tmp64;
|
||||
tmp64 = silk_RSHIFT_ROUND64( silk_SMULL( silk_SUB_SAT32(tmp2,
|
||||
MUL32_FRAC_Q( tmp1, rc_Q31, 31 ) ), rc_mult2), mult2Q);
|
||||
if( tmp64 > silk_int32_MAX || tmp64 < silk_int32_MIN ) {
|
||||
return 0;
|
||||
}
|
||||
A_QA[ k - n - 1 ] = ( opus_int32 )tmp64;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check for stability */
|
||||
if( ( Anew_QA[ 0 ] > A_LIMIT ) || ( Anew_QA[ 0 ] < -A_LIMIT ) ) {
|
||||
if( ( A_QA[ k ] > A_LIMIT ) || ( A_QA[ k ] < -A_LIMIT ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set RC equal to negated AR coef */
|
||||
rc_Q31 = -silk_LSHIFT( Anew_QA[ 0 ], 31 - QA );
|
||||
rc_Q31 = -silk_LSHIFT( A_QA[ 0 ], 31 - QA );
|
||||
|
||||
/* Range: [ 1 : 2^30 ] */
|
||||
rc_mult1_Q30 = ( (opus_int32)1 << 30 ) - silk_SMMUL( rc_Q31, rc_Q31 );
|
||||
rc_mult1_Q30 = silk_SUB32( SILK_FIX_CONST( 1, 30 ), silk_SMMUL( rc_Q31, rc_Q31 ) );
|
||||
|
||||
/* Update inverse gain */
|
||||
/* Range: [ 0 : 2^30 ] */
|
||||
invGain_Q30 = silk_LSHIFT( silk_SMMUL( invGain_Q30, rc_mult1_Q30 ), 2 );
|
||||
silk_assert( invGain_Q30 >= 0 );
|
||||
silk_assert( invGain_Q30 <= 1<<30 );
|
||||
silk_assert( invGain_Q30 >= 0 );
|
||||
silk_assert( invGain_Q30 <= ( 1 << 30 ) );
|
||||
if( invGain_Q30 < SILK_FIX_CONST( 1.0f / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return invGain_Q30;
|
||||
}
|
||||
|
||||
/* For input in Q12 domain */
|
||||
opus_int32 silk_LPC_inverse_pred_gain( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
opus_int32 silk_LPC_inverse_pred_gain_c( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
const opus_int16 *A_Q12, /* I Prediction coefficients, Q12 [order] */
|
||||
const opus_int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
opus_int k;
|
||||
opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
|
||||
opus_int32 *Anew_QA;
|
||||
opus_int32 Atmp_QA[ SILK_MAX_ORDER_LPC ];
|
||||
opus_int32 DC_resp = 0;
|
||||
|
||||
Anew_QA = Atmp_QA[ order & 1 ];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for( k = 0; k < order; k++ ) {
|
||||
DC_resp += (opus_int32)A_Q12[ k ];
|
||||
Anew_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
|
||||
Atmp_QA[ k ] = silk_LSHIFT32( (opus_int32)A_Q12[ k ], QA - 12 );
|
||||
}
|
||||
/* If the DC is unstable, we don't even need to do the full calculations */
|
||||
if( DC_resp >= 4096 ) {
|
||||
return 0;
|
||||
}
|
||||
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
|
||||
return LPC_inverse_pred_gain_QA_c( Atmp_QA, order );
|
||||
}
|
||||
|
||||
#ifdef FIXED_POINT
|
||||
|
||||
/* For input in Q24 domain */
|
||||
opus_int32 silk_LPC_inverse_pred_gain_Q24( /* O Returns inverse prediction gain in energy domain, Q30 */
|
||||
const opus_int32 *A_Q24, /* I Prediction coefficients [order] */
|
||||
const opus_int order /* I Prediction order */
|
||||
)
|
||||
{
|
||||
opus_int k;
|
||||
opus_int32 Atmp_QA[ 2 ][ SILK_MAX_ORDER_LPC ];
|
||||
opus_int32 *Anew_QA;
|
||||
|
||||
Anew_QA = Atmp_QA[ order & 1 ];
|
||||
|
||||
/* Increase Q domain of the AR coefficients */
|
||||
for( k = 0; k < order; k++ ) {
|
||||
Anew_QA[ k ] = silk_RSHIFT32( A_Q24[ k ], 24 - QA );
|
||||
}
|
||||
|
||||
return LPC_inverse_pred_gain_QA( Atmp_QA, order );
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -130,6 +130,6 @@ void silk_LP_variable_cutoff(
|
|||
|
||||
/* ARMA low-pass filtering */
|
||||
silk_assert( TRANSITION_NB == 3 && TRANSITION_NA == 2 );
|
||||
silk_biquad_alt( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length, 1);
|
||||
silk_biquad_alt_stride1( frame, B_Q28, A_Q28, psLP->In_LP_State, frame, frame_length);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -319,14 +319,6 @@ static OPUS_INLINE opus_int32 silk_ADD_POS_SAT32(opus_int64 a, opus_int64 b){
|
|||
return(tmp);
|
||||
}
|
||||
|
||||
#undef silk_ADD_POS_SAT64
|
||||
static OPUS_INLINE opus_int64 silk_ADD_POS_SAT64(opus_int64 a, opus_int64 b){
|
||||
opus_int64 tmp;
|
||||
ops_count += 1;
|
||||
tmp = ((((a)+(b)) & 0x8000000000000000LL) ? silk_int64_MAX : ((a)+(b)));
|
||||
return(tmp);
|
||||
}
|
||||
|
||||
#undef silk_LSHIFT8
|
||||
static OPUS_INLINE opus_int8 silk_LSHIFT8(opus_int8 a, opus_int32 shift){
|
||||
opus_int8 ret;
|
||||
|
@ -699,7 +691,7 @@ return(ret);
|
|||
|
||||
|
||||
#undef silk_LIMIT_32
|
||||
static OPUS_INLINE opus_int silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
|
||||
static OPUS_INLINE opus_int32 silk_LIMIT_32(opus_int32 a, opus_int32 limit1, opus_int32 limit2)
|
||||
{
|
||||
opus_int32 ret;
|
||||
ops_count += 6;
|
||||
|
|
|
@ -539,8 +539,7 @@ static OPUS_INLINE opus_int32 silk_DIV32_16_(opus_int32 a32, opus_int32 b32, cha
|
|||
no checking needed for silk_POS_SAT32
|
||||
no checking needed for silk_ADD_POS_SAT8
|
||||
no checking needed for silk_ADD_POS_SAT16
|
||||
no checking needed for silk_ADD_POS_SAT32
|
||||
no checking needed for silk_ADD_POS_SAT64 */
|
||||
no checking needed for silk_ADD_POS_SAT32 */
|
||||
|
||||
#undef silk_LSHIFT8
|
||||
#define silk_LSHIFT8(a,b) silk_LSHIFT8_((a), (b), __FILE__, __LINE__)
|
||||
|
|
|
@ -66,7 +66,8 @@ static OPUS_INLINE void silk_NLSF2A_find_poly(
|
|||
void silk_NLSF2A(
|
||||
opus_int16 *a_Q12, /* O monic whitening filter coefficients in Q12, [ d ] */
|
||||
const opus_int16 *NLSF, /* I normalized line spectral frequencies in Q15, [ d ] */
|
||||
const opus_int d /* I filter order (should be even) */
|
||||
const opus_int d, /* I filter order (should be even) */
|
||||
int arch /* I Run-time architecture */
|
||||
)
|
||||
{
|
||||
/* This ordering was found to maximize quality. It improves numerical accuracy of
|
||||
|
@ -83,15 +84,14 @@ void silk_NLSF2A(
|
|||
opus_int32 P[ SILK_MAX_ORDER_LPC / 2 + 1 ], Q[ SILK_MAX_ORDER_LPC / 2 + 1 ];
|
||||
opus_int32 Ptmp, Qtmp, f_int, f_frac, cos_val, delta;
|
||||
opus_int32 a32_QA1[ SILK_MAX_ORDER_LPC ];
|
||||
opus_int32 maxabs, absval, idx=0, sc_Q16;
|
||||
|
||||
silk_assert( LSF_COS_TAB_SZ_FIX == 128 );
|
||||
silk_assert( d==10||d==16 );
|
||||
celt_assert( d==10 || d==16 );
|
||||
|
||||
/* convert LSFs to 2*cos(LSF), using piecewise linear curve from table */
|
||||
ordering = d == 16 ? ordering16 : ordering10;
|
||||
for( k = 0; k < d; k++ ) {
|
||||
silk_assert(NLSF[k] >= 0 );
|
||||
silk_assert( NLSF[k] >= 0 );
|
||||
|
||||
/* f_int on a scale 0-127 (rounded down) */
|
||||
f_int = silk_RSHIFT( NLSF[k], 15 - 7 );
|
||||
|
@ -126,52 +126,15 @@ void silk_NLSF2A(
|
|||
a32_QA1[ d-k-1 ] = Qtmp - Ptmp; /* QA+1 */
|
||||
}
|
||||
|
||||
/* Limit the maximum absolute value of the prediction coefficients, so that they'll fit in int16 */
|
||||
for( i = 0; i < 10; i++ ) {
|
||||
/* Find maximum absolute value and its index */
|
||||
maxabs = 0;
|
||||
for( k = 0; k < d; k++ ) {
|
||||
absval = silk_abs( a32_QA1[k] );
|
||||
if( absval > maxabs ) {
|
||||
maxabs = absval;
|
||||
idx = k;
|
||||
}
|
||||
}
|
||||
maxabs = silk_RSHIFT_ROUND( maxabs, QA + 1 - 12 ); /* QA+1 -> Q12 */
|
||||
/* Convert int32 coefficients to Q12 int16 coefs */
|
||||
silk_LPC_fit( a_Q12, a32_QA1, 12, QA + 1, d );
|
||||
|
||||
if( maxabs > silk_int16_MAX ) {
|
||||
/* Reduce magnitude of prediction coefficients */
|
||||
maxabs = silk_min( maxabs, 163838 ); /* ( silk_int32_MAX >> 14 ) + silk_int16_MAX = 163838 */
|
||||
sc_Q16 = SILK_FIX_CONST( 0.999, 16 ) - silk_DIV32( silk_LSHIFT( maxabs - silk_int16_MAX, 14 ),
|
||||
silk_RSHIFT32( silk_MUL( maxabs, idx + 1), 2 ) );
|
||||
silk_bwexpander_32( a32_QA1, d, sc_Q16 );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( i == 10 ) {
|
||||
/* Reached the last iteration, clip the coefficients */
|
||||
for( i = 0; silk_LPC_inverse_pred_gain( a_Q12, d, arch ) == 0 && i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
|
||||
/* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
|
||||
/* on the unscaled coefficients, convert to Q12 and measure again */
|
||||
silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
|
||||
for( k = 0; k < d; k++ ) {
|
||||
a_Q12[ k ] = (opus_int16)silk_SAT16( silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ) ); /* QA+1 -> Q12 */
|
||||
a32_QA1[ k ] = silk_LSHIFT( (opus_int32)a_Q12[ k ], QA + 1 - 12 );
|
||||
}
|
||||
} else {
|
||||
for( k = 0; k < d; k++ ) {
|
||||
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
|
||||
}
|
||||
}
|
||||
|
||||
for( i = 0; i < MAX_LPC_STABILIZE_ITERATIONS; i++ ) {
|
||||
if( silk_LPC_inverse_pred_gain( a_Q12, d ) < SILK_FIX_CONST( 1.0 / MAX_PREDICTION_POWER_GAIN, 30 ) ) {
|
||||
/* Prediction coefficients are (too close to) unstable; apply bandwidth expansion */
|
||||
/* on the unscaled coefficients, convert to Q12 and measure again */
|
||||
silk_bwexpander_32( a32_QA1, d, 65536 - silk_LSHIFT( 2, i ) );
|
||||
for( k = 0; k < d; k++ ) {
|
||||
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
a_Q12[ k ] = (opus_int16)silk_RSHIFT_ROUND( a32_QA1[ k ], QA + 1 - 12 ); /* QA+1 -> Q12 */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue