Initial community commit

This commit is contained in:
Jef 2024-09-24 14:54:57 +02:00
parent 537bcbc862
commit fc06254474
16440 changed files with 4239995 additions and 2 deletions

View file

@ -0,0 +1,981 @@
/* Copyright (c) 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 FOUNDATION 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 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 "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,
0.351851f, 0.338330f, 0.311806f, 0.273300f, 0.224292f, 0.166664f, 0.102631f, 0.034654f,
-0.034654f,-0.102631f,-0.166664f,-0.224292f,-0.273300f,-0.311806f,-0.338330f,-0.351851f,
0.346760f, 0.293969f, 0.196424f, 0.068975f,-0.068975f,-0.196424f,-0.293969f,-0.346760f,
-0.346760f,-0.293969f,-0.196424f,-0.068975f, 0.068975f, 0.196424f, 0.293969f, 0.346760f,
0.338330f, 0.224292f, 0.034654f,-0.166664f,-0.311806f,-0.351851f,-0.273300f,-0.102631f,
0.102631f, 0.273300f, 0.351851f, 0.311806f, 0.166664f,-0.034654f,-0.224292f,-0.338330f,
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
0.326641f, 0.135299f,-0.135299f,-0.326641f,-0.326641f,-0.135299f, 0.135299f, 0.326641f,
0.311806f, 0.034654f,-0.273300f,-0.338330f,-0.102631f, 0.224292f, 0.351851f, 0.166664f,
-0.166664f,-0.351851f,-0.224292f, 0.102631f, 0.338330f, 0.273300f,-0.034654f,-0.311806f,
0.293969f,-0.068975f,-0.346760f,-0.196424f, 0.196424f, 0.346760f, 0.068975f,-0.293969f,
-0.293969f, 0.068975f, 0.346760f, 0.196424f,-0.196424f,-0.346760f,-0.068975f, 0.293969f,
0.273300f,-0.166664f,-0.338330f, 0.034654f, 0.351851f, 0.102631f,-0.311806f,-0.224292f,
0.224292f, 0.311806f,-0.102631f,-0.351851f,-0.034654f, 0.338330f, 0.166664f,-0.273300f,
};
static const float analysis_window[240] = {
0.000043f, 0.000171f, 0.000385f, 0.000685f, 0.001071f, 0.001541f, 0.002098f, 0.002739f,
0.003466f, 0.004278f, 0.005174f, 0.006156f, 0.007222f, 0.008373f, 0.009607f, 0.010926f,
0.012329f, 0.013815f, 0.015385f, 0.017037f, 0.018772f, 0.020590f, 0.022490f, 0.024472f,
0.026535f, 0.028679f, 0.030904f, 0.033210f, 0.035595f, 0.038060f, 0.040604f, 0.043227f,
0.045928f, 0.048707f, 0.051564f, 0.054497f, 0.057506f, 0.060591f, 0.063752f, 0.066987f,
0.070297f, 0.073680f, 0.077136f, 0.080665f, 0.084265f, 0.087937f, 0.091679f, 0.095492f,
0.099373f, 0.103323f, 0.107342f, 0.111427f, 0.115579f, 0.119797f, 0.124080f, 0.128428f,
0.132839f, 0.137313f, 0.141849f, 0.146447f, 0.151105f, 0.155823f, 0.160600f, 0.165435f,
0.170327f, 0.175276f, 0.180280f, 0.185340f, 0.190453f, 0.195619f, 0.200838f, 0.206107f,
0.211427f, 0.216797f, 0.222215f, 0.227680f, 0.233193f, 0.238751f, 0.244353f, 0.250000f,
0.255689f, 0.261421f, 0.267193f, 0.273005f, 0.278856f, 0.284744f, 0.290670f, 0.296632f,
0.302628f, 0.308658f, 0.314721f, 0.320816f, 0.326941f, 0.333097f, 0.339280f, 0.345492f,
0.351729f, 0.357992f, 0.364280f, 0.370590f, 0.376923f, 0.383277f, 0.389651f, 0.396044f,
0.402455f, 0.408882f, 0.415325f, 0.421783f, 0.428254f, 0.434737f, 0.441231f, 0.447736f,
0.454249f, 0.460770f, 0.467298f, 0.473832f, 0.480370f, 0.486912f, 0.493455f, 0.500000f,
0.506545f, 0.513088f, 0.519630f, 0.526168f, 0.532702f, 0.539230f, 0.545751f, 0.552264f,
0.558769f, 0.565263f, 0.571746f, 0.578217f, 0.584675f, 0.591118f, 0.597545f, 0.603956f,
0.610349f, 0.616723f, 0.623077f, 0.629410f, 0.635720f, 0.642008f, 0.648271f, 0.654508f,
0.660720f, 0.666903f, 0.673059f, 0.679184f, 0.685279f, 0.691342f, 0.697372f, 0.703368f,
0.709330f, 0.715256f, 0.721144f, 0.726995f, 0.732807f, 0.738579f, 0.744311f, 0.750000f,
0.755647f, 0.761249f, 0.766807f, 0.772320f, 0.777785f, 0.783203f, 0.788573f, 0.793893f,
0.799162f, 0.804381f, 0.809547f, 0.814660f, 0.819720f, 0.824724f, 0.829673f, 0.834565f,
0.839400f, 0.844177f, 0.848895f, 0.853553f, 0.858151f, 0.862687f, 0.867161f, 0.871572f,
0.875920f, 0.880203f, 0.884421f, 0.888573f, 0.892658f, 0.896677f, 0.900627f, 0.904508f,
0.908321f, 0.912063f, 0.915735f, 0.919335f, 0.922864f, 0.926320f, 0.929703f, 0.933013f,
0.936248f, 0.939409f, 0.942494f, 0.945503f, 0.948436f, 0.951293f, 0.954072f, 0.956773f,
0.959396f, 0.961940f, 0.964405f, 0.966790f, 0.969096f, 0.971321f, 0.973465f, 0.975528f,
0.977510f, 0.979410f, 0.981228f, 0.982963f, 0.984615f, 0.986185f, 0.987671f, 0.989074f,
0.990393f, 0.991627f, 0.992778f, 0.993844f, 0.994826f, 0.995722f, 0.996534f, 0.997261f,
0.997902f, 0.998459f, 0.998929f, 0.999315f, 0.999615f, 0.999829f, 0.999957f, 1.000000f,
};
static const int tbands[NB_TBANDS+1] = {
4, 8, 12, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 136, 160, 192, 240
};
#define NB_TONAL_SKIP_BANDS 9
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;
}
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);
}
void tonality_analysis_reset(TonalityAnalysisState *tonal)
{
/* Clear non-reusable fields. */
char *start = (char*)&tonal->TONALITY_ANALYSIS_RESET_START;
OPUS_CLEAR(start, sizeof(TonalityAnalysisState) - (start - (char*)tonal));
}
void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len)
{
int pos;
int curr_lookahead;
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;
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)
pos=0;
}
if (pos == tonal->write_pos)
pos--;
if (pos<0)
pos = DETECT_SIZE-1;
pos0 = pos;
OPUS_COPY(info_out, &tonal->info[pos], 1);
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++)
{
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--;
}
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);
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;
}
/* 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
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;
const kiss_fft_state *kfft;
VARDECL(kiss_fft_cpx, in);
VARDECL(kiss_fft_cpx, out);
int N = 480, N2=240;
float * OPUS_RESTRICT A = tonal->angle;
float * OPUS_RESTRICT dA = tonal->d_angle;
float * OPUS_RESTRICT d2A = tonal->d2_angle;
VARDECL(float, tonality);
VARDECL(float, noisiness);
float band_tonality[NB_TBANDS];
float logE[NB_TBANDS];
float BFCC[8];
float features[25];
float frame_tonality;
float max_frame_tonality;
/*float tw_sum=0;*/
float frame_noisiness;
const float pi4 = (float)(M_PI*M_PI*M_PI*M_PI);
float slope=0;
float frame_stationarity;
float relativeE;
float frame_probs[2];
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;
if (!tonal->initialized)
{
tonal->mem_fill = 240;
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;
/* Don't have enough to update the analysis */
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);
ALLOC(noisiness, 240, float);
for (i=0;i<N2;i++)
{
float w = analysis_window[i];
in[i].r = (kiss_fft_scalar)(w*tonal->inmem[i]);
in[i].i = (kiss_fft_scalar)(w*tonal->inmem[N2+i]);
in[N-i-1].r = (kiss_fft_scalar)(w*tonal->inmem[N-i-1]);
in[N-i-1].i = (kiss_fft_scalar)(w*tonal->inmem[N+N2-i-1]);
}
OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
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. */
if (celt_isnan(out[0].r))
{
info->valid = 0;
RESTORE_STACK;
return;
}
#endif
for (i=1;i<N2;i++)
{
float X1r, X2r, X1i, X2i;
float angle, d_angle, d2_angle;
float angle2, d_angle2, d2_angle2;
float mod1, mod2, avg_mod;
X1r = (float)out[i].r+out[N-i].r;
X1i = (float)out[i].i-out[N-i].i;
X2r = (float)out[i].i+out[N-i].i;
X2i = (float)out[N-i].r-out[i].r;
angle = (float)(.5f/M_PI)*fast_atan2f(X1i, X1r);
d_angle = angle - A[i];
d2_angle = d_angle - dA[i];
angle2 = (float)(.5f/M_PI)*fast_atan2f(X2i, X2r);
d_angle2 = angle2 - angle;
d2_angle2 = d_angle2 - d_angle;
mod1 = d2_angle - (float)float2int(d2_angle);
noisiness[i] = ABS16(mod1);
mod1 *= mod1;
mod1 *= mod1;
mod2 = d2_angle2 - (float)float2int(d2_angle2);
noisiness[i] += ABS16(mod2);
mod2 *= mod2;
mod2 *= 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;*/
info->activity = 0;
frame_noisiness = 0;
frame_stationarity = 0;
if (!tonal->count)
{
for (b=0;b<NB_TBANDS;b++)
{
tonal->lowE[b] = 1e10;
tonal->highE[b] = -1e10;
}
}
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;
float L1, L2;
float stationarity;
for (i=tbands[b];i<tbands[b+1];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;
binE = SCALE_ENER(binE);
E += binE;
tE += binE*MAX32(0, tonality[i]);
nE += binE*2.f*(.5f-noisiness[i]);
}
#ifndef FIXED_POINT
/* Check for extreme band energies that could cause NaNs later. */
if (!(E<1e9f) || celt_isnan(E))
{
info->valid = 0;
RESTORE_STACK;
return;
}
#endif
tonal->E[tonal->E_count][b] = E;
frame_noisiness += nE/(1e-15f+E);
frame_loudness += (float)sqrt(E+1e-10f);
logE[b] = (float)log(E+1e-10f);
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)
{
if (tonal->highE[b] - logE[b] > logE[b] - tonal->lowE[b])
tonal->highE[b] -= .01f;
else
tonal->lowE[b] += .01f;
}
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++)
{
L1 += (float)sqrt(tonal->E[i][b]);
L2 += tonal->E[i][b];
}
stationarity = MIN16(0.99f,L1/(float)sqrt(1e-15+NB_FRAMES*L2));
stationarity *= stationarity;
stationarity *= stationarity;
frame_stationarity += stationarity;
/*band_tonality[b] = tE/(1e-15+E)*/;
band_tonality[b] = MAX16(tE/(1e-15f+E), stationarity*tonal->prev_band_tonality[b]);
#if 0
if (b>=NB_TONAL_SKIP_BANDS)
{
frame_tonality += tweight[b]*band_tonality[b];
tw_sum += tweight[b];
}
#else
frame_tonality += band_tonality[b];
if (b>=NB_TBANDS-NB_TONAL_SKIP_BANDS)
frame_tonality -= band_tonality[b-NB_TBANDS+NB_TONAL_SKIP_BANDS];
#endif
max_frame_tonality = MAX16(max_frame_tonality, (1.f+.03f*(b-NB_TBANDS))*frame_tonality);
slope += band_tonality[b]*(b-8);
/*printf("%f %f ", band_tonality[b], stationarity);*/
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)));
noise_floor *= noise_floor;
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 = 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);
Em = MAX32(E, tonal->meanE[b]);
/* Consider the band "active" only if all these conditions are met:
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)
2) above the PCM quantization noise floor
We use b+1 because the first CELT band isn't included in tbands[]
*/
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-.003f, frame_loudness);
tonal->lowECount *= (1-alphaE);
if (frame_loudness < tonal->Etracker-30)
tonal->lowECount += alphaE;
for (i=0;i<8;i++)
{
float sum=0;
for (b=0;b<16;b++)
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 = .5f;
frame_noisiness /= NB_TBANDS;
#if 1
info->activity = frame_noisiness + (1-frame_noisiness)*relativeE;
#else
info->activity = .5*(1+frame_noisiness-frame_stationarity);
#endif
frame_tonality = (max_frame_tonality/(NB_TBANDS-NB_TONAL_SKIP_BANDS));
frame_tonality = MAX16(frame_tonality, tonal->prev_tonality*.8f);
tonal->prev_tonality = frame_tonality;
slope /= 8*8;
info->tonality_slope = slope;
tonal->E_count = (tonal->E_count+1)%NB_FRAMES;
tonal->count = IMIN(tonal->count+1, ANALYSIS_COUNT_MAX);
info->tonality = frame_tonality;
for (i=0;i<4;i++)
features[i] = -0.12299f*(BFCC[i]+tonal->mem[i+24]) + 0.49195f*(tonal->mem[i]+tonal->mem[i+16]) + 0.69693f*tonal->mem[i+8] - 1.4349f*tonal->cmean[i];
for (i=0;i<4;i++)
tonal->cmean[i] = (1-alpha)*tonal->cmean[i] + alpha*BFCC[i];
for (i=0;i<4;i++)
features[4+i] = 0.63246f*(BFCC[i]-tonal->mem[i+24]) + 0.31623f*(tonal->mem[i]-tonal->mem[i+16]);
for (i=0;i<3;i++)
features[8+i] = 0.53452f*(BFCC[i]+tonal->mem[i+24]) - 0.26726f*(tonal->mem[i]+tonal->mem[i+16]) -0.53452f*tonal->mem[i+8];
if (tonal->count > 5)
{
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++)
{
tonal->mem[i+24] = tonal->mem[i+16];
tonal->mem[i+16] = tonal->mem[i+8];
tonal->mem[i+8] = tonal->mem[i];
tonal->mem[i] = BFCC[i];
}
for (i=0;i<9;i++)
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;
compute_dense(&layer0, layer_out, features);
compute_gru(&layer1, tonal->rnn_state, layer_out);
compute_dense(&layer2, frame_probs, tonal->rnn_state);
/* Probability of speech or music vs noise */
info->activity_probability = frame_probs[1];
info->music_prob = frame_probs[0];
/*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");
#endif
info->bandwidth = bandwidth;
tonal->prev_bandwidth = bandwidth;
/*printf("%d %d\n", info->bandwidth, info->opus_bandwidth);*/
info->noisiness = frame_noisiness;
info->valid = 1;
RESTORE_STACK;
}
void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
{
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/50, analysis_frame_size);
pcm_len = analysis_frame_size - analysis->analysis_offset;
offset = analysis->analysis_offset;
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;
}
tonality_get_info(analysis, analysis_info, frame_size);
}
#endif /* DISABLE_FLOAT_API */

View file

@ -0,0 +1,103 @@
/* Copyright (c) 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 FOUNDATION 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 ANALYSIS_H
#define ANALYSIS_H
#include "celt.h"
#include "opus_private.h"
#include "mlp.h"
#define NB_FRAMES 8
#define NB_TBANDS 18
#define ANALYSIS_BUF_SIZE 720 /* 30 ms at 24 kHz */
/* 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];
float d2_angle[240];
opus_val32 inmem[ANALYSIS_BUF_SIZE];
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_TBANDS+1];
float mem[32];
float cmean[8];
float std[9];
float Etracker;
float lowECount;
int E_count;
int count;
int analysis_offset;
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;
/** Initialize a TonalityAnalysisState struct.
*
* This performs some possibly slow initialization steps which should
* 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, opus_int32 Fs);
/** Reset a TonalityAnalysisState stuct.
*
* Call this when there's a discontinuity in the data.
*/
void tonality_analysis_reset(TonalityAnalysisState *analysis);
void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
void run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *analysis_pcm,
int analysis_frame_size, int frame_size, int c1, int c2, int C, opus_int32 Fs,
int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
#endif

View file

@ -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
};

View file

@ -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 */

View file

@ -0,0 +1,144 @@
/* Copyright (c) 2008-2011 Octasic Inc.
2012-2017 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 FOUNDATION 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 <math.h>
#include "opus_types.h"
#include "opus_defines.h"
#include "arch.h"
#include "tansig_table.h"
#include "mlp.h"
static OPUS_INLINE float tansig_approx(float x)
{
int i;
float y, dy;
float sign=1;
/* Tests are reversed to catch NaNs */
if (!(x<8))
return 1;
if (!(x>-8))
return -1;
#ifndef FIXED_POINT
/* Another check in case of -ffast-math */
if (celt_isnan(x))
return 0;
#endif
if (x<0)
{
x=-x;
sign=-1;
}
i = (int)floor(.5f+25*x);
x -= .04f*i;
y = tansig_table[i];
dy = 1-y*y;
y = y + x*dy*(1 - y*x);
return sign*y;
}
static OPUS_INLINE float sigmoid_approx(float x)
{
return .5f + .5f*tansig_approx(.5f*x);
}
static void gemm_accum(float *out, const opus_int8 *weights, int rows, int cols, int col_stride, const float *x)
{
int i, j;
for (i=0;i<rows;i++)
{
for (j=0;j<cols;j++)
out[i] += weights[j*col_stride + i]*x[j];
}
}
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];
}

View file

@ -0,0 +1,60 @@
/* 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
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 FOUNDATION 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 _MLP_H_
#define _MLP_H_
#include "opus_types.h"
#define WEIGHTS_SCALE (1.f/128)
#define MAX_NEURONS 32
typedef struct {
const opus_int8 *bias;
const opus_int8 *input_weights;
int nb_inputs;
int nb_neurons;
int sigmoid;
} DenseLayer;
typedef struct {
const opus_int8 *bias;
const opus_int8 *input_weights;
const opus_int8 *recurrent_weights;
int nb_inputs;
int nb_neurons;
} GRULayer;
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_ */

View file

@ -0,0 +1,672 @@
/*This file is automatically generated from a Keras model*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "mlp.h"
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
};

View file

@ -0,0 +1,356 @@
/* Copyright (c) 2011 Xiph.Org Foundation, Skype Limited
Written by Jean-Marc Valin and Koen Vos */
/*
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 "opus.h"
#include "opus_private.h"
#ifndef DISABLE_FLOAT_API
OPUS_EXPORT void opus_pcm_soft_clip(float *_x, int N, int C, float *declip_mem)
{
int c;
int i;
float *x;
if (C<1 || N<1 || !_x || !declip_mem) return;
/* First thing: saturate everything to +/- 2 which is the highest level our
non-linearity can handle. At the point where the signal reaches +/-2,
the derivative will be zero anyway, so this doesn't introduce any
discontinuity in the derivative. */
for (i=0;i<N*C;i++)
_x[i] = MAX16(-2.f, MIN16(2.f, _x[i]));
for (c=0;c<C;c++)
{
float a;
float x0;
int curr;
x = _x+c;
a = declip_mem[c];
/* Continue applying the non-linearity from the previous frame to avoid
any discontinuity. */
for (i=0;i<N;i++)
{
if (x[i*C]*a>=0)
break;
x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
}
curr=0;
x0 = x[0];
while(1)
{
int start, end;
float maxval;
int special=0;
int peak_pos;
for (i=curr;i<N;i++)
{
if (x[i*C]>1 || x[i*C]<-1)
break;
}
if (i==N)
{
a=0;
break;
}
peak_pos = i;
start=end=i;
maxval=ABS16(x[i*C]);
/* Look for first zero crossing before clipping */
while (start>0 && x[i*C]*x[(start-1)*C]>=0)
start--;
/* Look for first zero crossing after clipping */
while (end<N && x[i*C]*x[end*C]>=0)
{
/* Look for other peaks until the next zero-crossing. */
if (ABS16(x[end*C])>maxval)
{
maxval = ABS16(x[end*C]);
peak_pos = end;
}
end++;
}
/* Detect the special case where we clip before the first zero crossing */
special = (start==0 && x[i*C]*x[0]>=0);
/* Compute a such that maxval + a*maxval^2 = 1 */
a=(maxval-1)/(maxval*maxval);
/* 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-7f;
if (x[i*C]>0)
a = -a;
/* Apply soft clipping */
for (i=start;i<end;i++)
x[i*C] = x[i*C]+a*x[i*C]*x[i*C];
if (special && peak_pos>=2)
{
/* Add a linear ramp from the first sample to the signal peak.
This avoids a discontinuity at the beginning of the frame. */
float delta;
float offset = x0-x[0];
delta = offset / peak_pos;
for (i=curr;i<peak_pos;i++)
{
offset -= delta;
x[i*C] += offset;
x[i*C] = MAX16(-1.f, MIN16(1.f, x[i*C]));
}
}
curr = end;
if (curr==N)
break;
}
declip_mem[c] = a;
}
}
#endif
int encode_size(int size, unsigned char *data)
{
if (size < 252)
{
data[0] = size;
return 1;
} else {
data[0] = 252+(size&0x3);
data[1] = (size-(int)data[0])>>2;
return 2;
}
}
static int parse_size(const unsigned char *data, opus_int32 len, opus_int16 *size)
{
if (len<1)
{
*size = -1;
return -1;
} else if (data[0]<252)
{
*size = data[0];
return 1;
} else if (len<2)
{
*size = -1;
return -1;
} else {
*size = 4*data[1] + data[0];
return 2;
}
}
int opus_packet_get_samples_per_frame(const unsigned char *data,
opus_int32 Fs)
{
int audiosize;
if (data[0]&0x80)
{
audiosize = ((data[0]>>3)&0x3);
audiosize = (Fs<<audiosize)/400;
} else if ((data[0]&0x60) == 0x60)
{
audiosize = (data[0]&0x08) ? Fs/50 : Fs/100;
} else {
audiosize = ((data[0]>>3)&0x3);
if (audiosize == 3)
audiosize = Fs*60/1000;
else
audiosize = (Fs<<audiosize)/100;
}
return audiosize;
}
int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
int self_delimited, unsigned char *out_toc,
const unsigned char *frames[48], opus_int16 size[48],
int *payload_offset, opus_int32 *packet_offset)
{
int i, bytes;
int count;
int cbr;
unsigned char ch, toc;
int framesize;
opus_int32 last_size;
opus_int32 pad = 0;
const unsigned char *data0 = data;
if (size==NULL || len<0)
return OPUS_BAD_ARG;
if (len==0)
return OPUS_INVALID_PACKET;
framesize = opus_packet_get_samples_per_frame(data, 48000);
cbr = 0;
toc = *data++;
len--;
last_size = len;
switch (toc&0x3)
{
/* One frame */
case 0:
count=1;
break;
/* Two CBR frames */
case 1:
count=2;
cbr = 1;
if (!self_delimited)
{
if (len&0x1)
return OPUS_INVALID_PACKET;
last_size = len/2;
/* If last_size doesn't fit in size[0], we'll catch it later */
size[0] = (opus_int16)last_size;
}
break;
/* Two VBR frames */
case 2:
count = 2;
bytes = parse_size(data, len, size);
len -= bytes;
if (size[0]<0 || size[0] > len)
return OPUS_INVALID_PACKET;
data += bytes;
last_size = len-size[0];
break;
/* Multiple CBR/VBR frames (from 0 to 120 ms) */
default: /*case 3:*/
if (len<1)
return OPUS_INVALID_PACKET;
/* Number of frames encoded in bits 0 to 5 */
ch = *data++;
count = ch&0x3F;
if (count <= 0 || framesize*(opus_int32)count > 5760)
return OPUS_INVALID_PACKET;
len--;
/* Padding flag is bit 6 */
if (ch&0x40)
{
int p;
do {
int tmp;
if (len<=0)
return OPUS_INVALID_PACKET;
p = *data++;
len--;
tmp = p==255 ? 254: p;
len -= tmp;
pad += tmp;
} while (p==255);
}
if (len<0)
return OPUS_INVALID_PACKET;
/* VBR flag is bit 7 */
cbr = !(ch&0x80);
if (!cbr)
{
/* VBR case */
last_size = len;
for (i=0;i<count-1;i++)
{
bytes = parse_size(data, len, size+i);
len -= bytes;
if (size[i]<0 || size[i] > len)
return OPUS_INVALID_PACKET;
data += bytes;
last_size -= bytes+size[i];
}
if (last_size<0)
return OPUS_INVALID_PACKET;
} else if (!self_delimited)
{
/* CBR case */
last_size = len/count;
if (last_size*count!=len)
return OPUS_INVALID_PACKET;
for (i=0;i<count-1;i++)
size[i] = (opus_int16)last_size;
}
break;
}
/* Self-delimited framing has an extra size for the last frame. */
if (self_delimited)
{
bytes = parse_size(data, len, size+count-1);
len -= bytes;
if (size[count-1]<0 || size[count-1] > len)
return OPUS_INVALID_PACKET;
data += bytes;
/* For CBR packets, apply the size to all the frames. */
if (cbr)
{
if (size[count-1]*count > len)
return OPUS_INVALID_PACKET;
for (i=0;i<count-1;i++)
size[i] = size[count-1];
} else if (bytes+size[count-1] > last_size)
return OPUS_INVALID_PACKET;
} else
{
/* Because it's not encoded explicitly, it's possible the size of the
last packet (or all the packets, for the CBR case) is larger than
1275. Reject them here.*/
if (last_size > 1275)
return OPUS_INVALID_PACKET;
size[count-1] = (opus_int16)last_size;
}
if (payload_offset)
*payload_offset = (int)(data-data0);
for (i=0;i<count;i++)
{
if (frames)
frames[i] = data;
data += size[i];
}
if (packet_offset)
*packet_offset = pad+(opus_int32)(data-data0);
if (out_toc)
*out_toc = toc;
return count;
}
int opus_packet_parse(const unsigned char *data, opus_int32 len,
unsigned char *out_toc, const unsigned char *frames[48],
opus_int16 size[48], int *payload_offset)
{
return opus_packet_parse_impl(data, len, 0, out_toc,
frames, size, payload_offset, NULL);
}

View file

@ -0,0 +1,382 @@
/* Copyright (c) 2011-2012 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define OPUS_PI (3.14159265F)
#define OPUS_COSF(_x) ((float)cos(_x))
#define OPUS_SINF(_x) ((float)sin(_x))
static void *check_alloc(void *_ptr){
if(_ptr==NULL){
fprintf(stderr,"Out of memory.\n");
exit(EXIT_FAILURE);
}
return _ptr;
}
static void *opus_malloc(size_t _size){
return check_alloc(malloc(_size));
}
static void *opus_realloc(void *_ptr,size_t _size){
return check_alloc(realloc(_ptr,_size));
}
static size_t read_pcm16(float **_samples,FILE *_fin,int _nchannels){
unsigned char buf[1024];
float *samples;
size_t nsamples;
size_t csamples;
size_t xi;
size_t nread;
samples=NULL;
nsamples=csamples=0;
for(;;){
nread=fread(buf,2*_nchannels,1024/(2*_nchannels),_fin);
if(nread<=0)break;
if(nsamples+nread>csamples){
do csamples=csamples<<1|1;
while(nsamples+nread>csamples);
samples=(float *)opus_realloc(samples,
_nchannels*csamples*sizeof(*samples));
}
for(xi=0;xi<nread;xi++){
int ci;
for(ci=0;ci<_nchannels;ci++){
int s;
s=buf[2*(xi*_nchannels+ci)+1]<<8|buf[2*(xi*_nchannels+ci)];
s=((s&0xFFFF)^0x8000)-0x8000;
samples[(nsamples+xi)*_nchannels+ci]=s;
}
}
nsamples+=nread;
}
*_samples=(float *)opus_realloc(samples,
_nchannels*nsamples*sizeof(*samples));
return nsamples;
}
static void band_energy(float *_out,float *_ps,const int *_bands,int _nbands,
const float *_in,int _nchannels,size_t _nframes,int _window_sz,
int _step,int _downsample){
float *window;
float *x;
float *c;
float *s;
size_t xi;
int xj;
int ps_sz;
window=(float *)opus_malloc((3+_nchannels)*_window_sz*sizeof(*window));
c=window+_window_sz;
s=c+_window_sz;
x=s+_window_sz;
ps_sz=_window_sz/2;
for(xj=0;xj<_window_sz;xj++){
window[xj]=0.5F-0.5F*OPUS_COSF((2*OPUS_PI/(_window_sz-1))*xj);
}
for(xj=0;xj<_window_sz;xj++){
c[xj]=OPUS_COSF((2*OPUS_PI/_window_sz)*xj);
}
for(xj=0;xj<_window_sz;xj++){
s[xj]=OPUS_SINF((2*OPUS_PI/_window_sz)*xj);
}
for(xi=0;xi<_nframes;xi++){
int ci;
int xk;
int bi;
for(ci=0;ci<_nchannels;ci++){
for(xk=0;xk<_window_sz;xk++){
x[ci*_window_sz+xk]=window[xk]*_in[(xi*_step+xk)*_nchannels+ci];
}
}
for(bi=xj=0;bi<_nbands;bi++){
float p[2]={0};
for(;xj<_bands[bi+1];xj++){
for(ci=0;ci<_nchannels;ci++){
float re;
float im;
int ti;
ti=0;
re=im=0;
for(xk=0;xk<_window_sz;xk++){
re+=c[ti]*x[ci*_window_sz+xk];
im-=s[ti]*x[ci*_window_sz+xk];
ti+=xj;
if(ti>=_window_sz)ti-=_window_sz;
}
re*=_downsample;
im*=_downsample;
_ps[(xi*ps_sz+xj)*_nchannels+ci]=re*re+im*im+100000;
p[ci]+=_ps[(xi*ps_sz+xj)*_nchannels+ci];
}
}
if(_out){
_out[(xi*_nbands+bi)*_nchannels]=p[0]/(_bands[bi+1]-_bands[bi]);
if(_nchannels==2){
_out[(xi*_nbands+bi)*_nchannels+1]=p[1]/(_bands[bi+1]-_bands[bi]);
}
}
}
}
free(window);
}
#define NBANDS (21)
#define NFREQS (240)
/*Bands on which we compute the pseudo-NMR (Bark-derived
CELT bands).*/
static const int BANDS[NBANDS+1]={
0,2,4,6,8,10,12,14,16,20,24,28,32,40,48,56,68,80,96,120,156,200
};
#define TEST_WIN_SIZE (480)
#define TEST_WIN_STEP (120)
int main(int _argc,const char **_argv){
FILE *fin1;
FILE *fin2;
float *x;
float *y;
float *xb;
float *X;
float *Y;
double err;
float Q;
size_t xlength;
size_t ylength;
size_t nframes;
size_t xi;
int ci;
int xj;
int bi;
int nchannels;
unsigned rate;
int downsample;
int ybands;
int yfreqs;
int max_compare;
if(_argc<3||_argc>6){
fprintf(stderr,"Usage: %s [-s] [-r rate2] <file1.sw> <file2.sw>\n",
_argv[0]);
return EXIT_FAILURE;
}
nchannels=1;
if(strcmp(_argv[1],"-s")==0){
nchannels=2;
_argv++;
}
rate=48000;
ybands=NBANDS;
yfreqs=NFREQS;
downsample=1;
if(strcmp(_argv[1],"-r")==0){
rate=atoi(_argv[2]);
if(rate!=8000&&rate!=12000&&rate!=16000&&rate!=24000&&rate!=48000){
fprintf(stderr,
"Sampling rate must be 8000, 12000, 16000, 24000, or 48000\n");
return EXIT_FAILURE;
}
downsample=48000/rate;
switch(rate){
case 8000:ybands=13;break;
case 12000:ybands=15;break;
case 16000:ybands=17;break;
case 24000:ybands=19;break;
}
yfreqs=NFREQS/downsample;
_argv+=2;
}
fin1=fopen(_argv[1],"rb");
if(fin1==NULL){
fprintf(stderr,"Error opening '%s'.\n",_argv[1]);
return EXIT_FAILURE;
}
fin2=fopen(_argv[2],"rb");
if(fin2==NULL){
fprintf(stderr,"Error opening '%s'.\n",_argv[2]);
fclose(fin1);
return EXIT_FAILURE;
}
/*Read in the data and allocate scratch space.*/
xlength=read_pcm16(&x,fin1,2);
if(nchannels==1){
for(xi=0;xi<xlength;xi++)x[xi]=.5*(x[2*xi]+x[2*xi+1]);
}
fclose(fin1);
ylength=read_pcm16(&y,fin2,nchannels);
fclose(fin2);
if(xlength!=ylength*downsample){
fprintf(stderr,"Sample counts do not match (%lu!=%lu).\n",
(unsigned long)xlength,(unsigned long)ylength*downsample);
return EXIT_FAILURE;
}
if(xlength<TEST_WIN_SIZE){
fprintf(stderr,"Insufficient sample data (%lu<%i).\n",
(unsigned long)xlength,TEST_WIN_SIZE);
return EXIT_FAILURE;
}
nframes=(xlength-TEST_WIN_SIZE+TEST_WIN_STEP)/TEST_WIN_STEP;
xb=(float *)opus_malloc(nframes*NBANDS*nchannels*sizeof(*xb));
X=(float *)opus_malloc(nframes*NFREQS*nchannels*sizeof(*X));
Y=(float *)opus_malloc(nframes*yfreqs*nchannels*sizeof(*Y));
/*Compute the per-band spectral energy of the original signal
and the error.*/
band_energy(xb,X,BANDS,NBANDS,x,nchannels,nframes,
TEST_WIN_SIZE,TEST_WIN_STEP,1);
free(x);
band_energy(NULL,Y,BANDS,ybands,y,nchannels,nframes,
TEST_WIN_SIZE/downsample,TEST_WIN_STEP/downsample,downsample);
free(y);
for(xi=0;xi<nframes;xi++){
/*Frequency masking (low to high): 10 dB/Bark slope.*/
for(bi=1;bi<NBANDS;bi++){
for(ci=0;ci<nchannels;ci++){
xb[(xi*NBANDS+bi)*nchannels+ci]+=
0.1F*xb[(xi*NBANDS+bi-1)*nchannels+ci];
}
}
/*Frequency masking (high to low): 15 dB/Bark slope.*/
for(bi=NBANDS-1;bi-->0;){
for(ci=0;ci<nchannels;ci++){
xb[(xi*NBANDS+bi)*nchannels+ci]+=
0.03F*xb[(xi*NBANDS+bi+1)*nchannels+ci];
}
}
if(xi>0){
/*Temporal masking: -3 dB/2.5ms slope.*/
for(bi=0;bi<NBANDS;bi++){
for(ci=0;ci<nchannels;ci++){
xb[(xi*NBANDS+bi)*nchannels+ci]+=
0.5F*xb[((xi-1)*NBANDS+bi)*nchannels+ci];
}
}
}
/* Allowing some cross-talk */
if(nchannels==2){
for(bi=0;bi<NBANDS;bi++){
float l,r;
l=xb[(xi*NBANDS+bi)*nchannels+0];
r=xb[(xi*NBANDS+bi)*nchannels+1];
xb[(xi*NBANDS+bi)*nchannels+0]+=0.01F*r;
xb[(xi*NBANDS+bi)*nchannels+1]+=0.01F*l;
}
}
/* Apply masking */
for(bi=0;bi<ybands;bi++){
for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
for(ci=0;ci<nchannels;ci++){
X[(xi*NFREQS+xj)*nchannels+ci]+=
0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
Y[(xi*yfreqs+xj)*nchannels+ci]+=
0.1F*xb[(xi*NBANDS+bi)*nchannels+ci];
}
}
}
}
/* Average of consecutive frames to make comparison slightly less sensitive */
for(bi=0;bi<ybands;bi++){
for(xj=BANDS[bi];xj<BANDS[bi+1];xj++){
for(ci=0;ci<nchannels;ci++){
float xtmp;
float ytmp;
xtmp = X[xj*nchannels+ci];
ytmp = Y[xj*nchannels+ci];
for(xi=1;xi<nframes;xi++){
float xtmp2;
float ytmp2;
xtmp2 = X[(xi*NFREQS+xj)*nchannels+ci];
ytmp2 = Y[(xi*yfreqs+xj)*nchannels+ci];
X[(xi*NFREQS+xj)*nchannels+ci] += xtmp;
Y[(xi*yfreqs+xj)*nchannels+ci] += ytmp;
xtmp = xtmp2;
ytmp = ytmp2;
}
}
}
}
/*If working at a lower sampling rate, don't take into account the last
300 Hz to allow for different transition bands.
For 12 kHz, we don't skip anything, because the last band already skips
400 Hz.*/
if(rate==48000)max_compare=BANDS[NBANDS];
else if(rate==12000)max_compare=BANDS[ybands];
else max_compare=BANDS[ybands]-3;
err=0;
for(xi=0;xi<nframes;xi++){
double Ef;
Ef=0;
for(bi=0;bi<ybands;bi++){
double Eb;
Eb=0;
for(xj=BANDS[bi];xj<BANDS[bi+1]&&xj<max_compare;xj++){
for(ci=0;ci<nchannels;ci++){
float re;
float im;
re=Y[(xi*yfreqs+xj)*nchannels+ci]/X[(xi*NFREQS+xj)*nchannels+ci];
im=re-log(re)-1;
/*Make comparison less sensitive around the SILK/CELT cross-over to
allow for mode freedom in the filters.*/
if(xj>=79&&xj<=81)im*=0.1F;
if(xj==80)im*=0.1F;
Eb+=im;
}
}
Eb /= (BANDS[bi+1]-BANDS[bi])*nchannels;
Ef += Eb*Eb;
}
/*Using a fixed normalization value means we're willing to accept slightly
lower quality for lower sampling rates.*/
Ef/=NBANDS;
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){
fprintf(stderr,"Test vector FAILS\n");
fprintf(stderr,"Internal weighted error is %f\n",err);
return EXIT_FAILURE;
}
else{
fprintf(stderr,"Test vector PASSES\n");
fprintf(stderr,
"Opus quality metric: %.1f %% (internal weighted error is %f)\n",Q,err);
return EXIT_SUCCESS;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,892 @@
/* Copyright (c) 2007-2008 CSIRO
Copyright (c) 2007-2009 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
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "opus.h"
#include "debug.h"
#include "opus_types.h"
#include "opus_private.h"
#include "opus_multistream.h"
#define MAX_PACKET 1500
void print_usage( char* argv[] )
{
fprintf(stderr, "Usage: %s [-e] <application> <sampling rate (Hz)> <channels (1/2)> "
"<bits per second> [options] <input> <output>\n", argv[0]);
fprintf(stderr, " %s -d <sampling rate (Hz)> <channels (1/2)> "
"[options] <input> <output>\n\n", argv[0]);
fprintf(stderr, "application: voip | audio | restricted-lowdelay\n" );
fprintf(stderr, "options:\n" );
fprintf(stderr, "-e : only runs the encoder (output the bit-stream)\n" );
fprintf(stderr, "-d : only runs the decoder (reads the bit-stream as input)\n" );
fprintf(stderr, "-cbr : enable constant bitrate; default: variable bitrate\n" );
fprintf(stderr, "-cvbr : enable constrained variable bitrate; default: unconstrained\n" );
fprintf(stderr, "-delayed-decision : use look-ahead for speech/music detection (experts only); default: disabled\n" );
fprintf(stderr, "-bandwidth <NB|MB|WB|SWB|FB> : audio bandwidth (from narrowband to fullband); default: sampling rate\n" );
fprintf(stderr, "-framesize <2.5|5|10|20|40|60|80|100|120> : frame size in ms; default: 20 \n" );
fprintf(stderr, "-max_payload <bytes> : maximum payload size in bytes, default: 1024\n" );
fprintf(stderr, "-complexity <comp> : complexity, 0 (lowest) ... 10 (highest); default: 10\n" );
fprintf(stderr, "-inbandfec : enable SILK inband FEC\n" );
fprintf(stderr, "-forcemono : force mono encoding, even for stereo input\n" );
fprintf(stderr, "-dtx : enable SILK DTX\n" );
fprintf(stderr, "-loss <perc> : simulate packet loss, in percent (0-100); default: 0\n" );
}
static void int_to_char(opus_uint32 i, unsigned char ch[4])
{
ch[0] = i>>24;
ch[1] = (i>>16)&0xFF;
ch[2] = (i>>8)&0xFF;
ch[3] = i&0xFF;
}
static opus_uint32 char_to_int(unsigned char ch[4])
{
return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
| ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3];
}
#define check_encoder_option(decode_only, opt) do {if (decode_only) {fprintf(stderr, "option %s is only for encoding\n", opt); goto failure;}} while(0)
static const int silk8_test[][4] = {
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*3, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960*2, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2}
};
static const int silk12_test[][4] = {
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*3, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960*2, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 960, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_MEDIUMBAND, 480, 2}
};
static const int silk16_test[][4] = {
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*3, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960*2, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2}
};
static const int hybrid24_test[][4] = {
{MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2}
};
static const int hybrid48_test[][4] = {
{MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
{MODE_SILK_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2}
};
static const int celt_test[][4] = {
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 1},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 960, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 960, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 960, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 480, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 480, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 480, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 240, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 240, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 240, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_SUPERWIDEBAND, 120, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_WIDEBAND, 120, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_NARROWBAND, 120, 2},
};
static const int celt_hq_test[][4] = {
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 960, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 480, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 240, 2},
{MODE_CELT_ONLY, OPUS_BANDWIDTH_FULLBAND, 120, 2},
};
#if 0 /* This is a hack that replaces the normal encoder/decoder with the multistream version */
#define OpusEncoder OpusMSEncoder
#define OpusDecoder OpusMSDecoder
#define opus_encode opus_multistream_encode
#define opus_decode opus_multistream_decode
#define opus_encoder_ctl opus_multistream_encoder_ctl
#define opus_decoder_ctl opus_multistream_decoder_ctl
#define opus_encoder_create ms_opus_encoder_create
#define opus_decoder_create ms_opus_decoder_create
#define opus_encoder_destroy opus_multistream_encoder_destroy
#define opus_decoder_destroy opus_multistream_decoder_destroy
static OpusEncoder *ms_opus_encoder_create(opus_int32 Fs, int channels, int application, int *error)
{
int streams, coupled_streams;
unsigned char mapping[256];
return (OpusEncoder *)opus_multistream_surround_encoder_create(Fs, channels, 1, &streams, &coupled_streams, mapping, application, error);
}
static OpusDecoder *ms_opus_decoder_create(opus_int32 Fs, int channels, int *error)
{
int streams;
int coupled_streams;
unsigned char mapping[256]={0,1};
streams = 1;
coupled_streams = channels==2;
return (OpusDecoder *)opus_multistream_decoder_create(Fs, channels, streams, coupled_streams, mapping, error);
}
#endif
int main(int argc, char *argv[])
{
int err;
char *inFile, *outFile;
FILE *fin=NULL;
FILE *fout=NULL;
OpusEncoder *enc=NULL;
OpusDecoder *dec=NULL;
int args;
int len[2];
int frame_size, channels;
opus_int32 bitrate_bps=0;
unsigned char *data[2] = {NULL, NULL};
unsigned char *fbytes=NULL;
opus_int32 sampling_rate;
int use_vbr;
int max_payload_bytes;
int complexity;
int use_inbandfec;
int use_dtx;
int forcechannels;
int cvbr = 0;
int packet_loss_perc;
opus_int32 count=0, count_act=0;
int k;
opus_int32 skip=0;
int stop=0;
short *in=NULL;
short *out=NULL;
int application=OPUS_APPLICATION_AUDIO;
double bits=0.0, bits_max=0.0, bits_act=0.0, bits2=0.0, nrg;
double tot_samples=0;
opus_uint64 tot_in, tot_out;
int bandwidth=OPUS_AUTO;
const char *bandwidth_string;
int lost = 0, lost_prev = 1;
int toggle = 0;
opus_uint32 enc_final_range[2];
opus_uint32 dec_final_range;
int encode_only=0, decode_only=0;
int max_frame_size = 48000*2;
size_t num_read;
int curr_read=0;
int sweep_bps = 0;
int random_framesize=0, newsize=0, delayed_celt=0;
int sweep_max=0, sweep_min=0;
int random_fec=0;
const int (*mode_list)[4]=NULL;
int nb_modes_in_list=0;
int curr_mode=0;
int curr_mode_count=0;
int mode_switch_time = 48000;
int nb_encoded=0;
int remaining=0;
int variable_duration=OPUS_FRAMESIZE_ARG;
int delayed_decision=0;
int ret = EXIT_FAILURE;
if (argc < 5 )
{
print_usage( argv );
goto failure;
}
tot_in=tot_out=0;
fprintf(stderr, "%s\n", opus_get_version_string());
args = 1;
if (strcmp(argv[args], "-e")==0)
{
encode_only = 1;
args++;
} else if (strcmp(argv[args], "-d")==0)
{
decode_only = 1;
args++;
}
if (!decode_only && argc < 7 )
{
print_usage( argv );
goto failure;
}
if (!decode_only)
{
if (strcmp(argv[args], "voip")==0)
application = OPUS_APPLICATION_VOIP;
else if (strcmp(argv[args], "restricted-lowdelay")==0)
application = OPUS_APPLICATION_RESTRICTED_LOWDELAY;
else if (strcmp(argv[args], "audio")!=0) {
fprintf(stderr, "unknown application: %s\n", argv[args]);
print_usage(argv);
goto failure;
}
args++;
}
sampling_rate = (opus_int32)atol(argv[args]);
args++;
if (sampling_rate != 8000 && sampling_rate != 12000
&& sampling_rate != 16000 && sampling_rate != 24000
&& sampling_rate != 48000)
{
fprintf(stderr, "Supported sampling rates are 8000, 12000, "
"16000, 24000 and 48000.\n");
goto failure;
}
frame_size = sampling_rate/50;
channels = atoi(argv[args]);
args++;
if (channels < 1 || channels > 2)
{
fprintf(stderr, "Opus_demo supports only 1 or 2 channels.\n");
goto failure;
}
if (!decode_only)
{
bitrate_bps = (opus_int32)atol(argv[args]);
args++;
}
/* defaults: */
use_vbr = 1;
max_payload_bytes = MAX_PACKET;
complexity = 10;
use_inbandfec = 0;
forcechannels = OPUS_AUTO;
use_dtx = 0;
packet_loss_perc = 0;
while( args < argc - 2 ) {
/* process command line options */
if( strcmp( argv[ args ], "-cbr" ) == 0 ) {
check_encoder_option(decode_only, "-cbr");
use_vbr = 0;
args++;
} else if( strcmp( argv[ args ], "-bandwidth" ) == 0 ) {
check_encoder_option(decode_only, "-bandwidth");
if (strcmp(argv[ args + 1 ], "NB")==0)
bandwidth = OPUS_BANDWIDTH_NARROWBAND;
else if (strcmp(argv[ args + 1 ], "MB")==0)
bandwidth = OPUS_BANDWIDTH_MEDIUMBAND;
else if (strcmp(argv[ args + 1 ], "WB")==0)
bandwidth = OPUS_BANDWIDTH_WIDEBAND;
else if (strcmp(argv[ args + 1 ], "SWB")==0)
bandwidth = OPUS_BANDWIDTH_SUPERWIDEBAND;
else if (strcmp(argv[ args + 1 ], "FB")==0)
bandwidth = OPUS_BANDWIDTH_FULLBAND;
else {
fprintf(stderr, "Unknown bandwidth %s. "
"Supported are NB, MB, WB, SWB, FB.\n",
argv[ args + 1 ]);
goto failure;
}
args += 2;
} else if( strcmp( argv[ args ], "-framesize" ) == 0 ) {
check_encoder_option(decode_only, "-framesize");
if (strcmp(argv[ args + 1 ], "2.5")==0)
frame_size = sampling_rate/400;
else if (strcmp(argv[ args + 1 ], "5")==0)
frame_size = sampling_rate/200;
else if (strcmp(argv[ args + 1 ], "10")==0)
frame_size = sampling_rate/100;
else if (strcmp(argv[ args + 1 ], "20")==0)
frame_size = sampling_rate/50;
else if (strcmp(argv[ args + 1 ], "40")==0)
frame_size = sampling_rate/25;
else if (strcmp(argv[ args + 1 ], "60")==0)
frame_size = 3*sampling_rate/50;
else if (strcmp(argv[ args + 1 ], "80")==0)
frame_size = 4*sampling_rate/50;
else if (strcmp(argv[ args + 1 ], "100")==0)
frame_size = 5*sampling_rate/50;
else if (strcmp(argv[ args + 1 ], "120")==0)
frame_size = 6*sampling_rate/50;
else {
fprintf(stderr, "Unsupported frame size: %s ms. "
"Supported are 2.5, 5, 10, 20, 40, 60, 80, 100, 120.\n",
argv[ args + 1 ]);
goto failure;
}
args += 2;
} else if( strcmp( argv[ args ], "-max_payload" ) == 0 ) {
check_encoder_option(decode_only, "-max_payload");
max_payload_bytes = atoi( argv[ args + 1 ] );
args += 2;
} else if( strcmp( argv[ args ], "-complexity" ) == 0 ) {
check_encoder_option(decode_only, "-complexity");
complexity = atoi( argv[ args + 1 ] );
args += 2;
} else if( strcmp( argv[ args ], "-inbandfec" ) == 0 ) {
use_inbandfec = 1;
args++;
} else if( strcmp( argv[ args ], "-forcemono" ) == 0 ) {
check_encoder_option(decode_only, "-forcemono");
forcechannels = 1;
args++;
} else if( strcmp( argv[ args ], "-cvbr" ) == 0 ) {
check_encoder_option(decode_only, "-cvbr");
cvbr = 1;
args++;
} else if( strcmp( argv[ args ], "-delayed-decision" ) == 0 ) {
check_encoder_option(decode_only, "-delayed-decision");
delayed_decision = 1;
args++;
} else if( strcmp( argv[ args ], "-dtx") == 0 ) {
check_encoder_option(decode_only, "-dtx");
use_dtx = 1;
args++;
} else if( strcmp( argv[ args ], "-loss" ) == 0 ) {
packet_loss_perc = atoi( argv[ args + 1 ] );
args += 2;
} else if( strcmp( argv[ args ], "-sweep" ) == 0 ) {
check_encoder_option(decode_only, "-sweep");
sweep_bps = atoi( argv[ args + 1 ] );
args += 2;
} else if( strcmp( argv[ args ], "-random_framesize" ) == 0 ) {
check_encoder_option(decode_only, "-random_framesize");
random_framesize = 1;
args++;
} else if( strcmp( argv[ args ], "-sweep_max" ) == 0 ) {
check_encoder_option(decode_only, "-sweep_max");
sweep_max = atoi( argv[ args + 1 ] );
args += 2;
} else if( strcmp( argv[ args ], "-random_fec" ) == 0 ) {
check_encoder_option(decode_only, "-random_fec");
random_fec = 1;
args++;
} else if( strcmp( argv[ args ], "-silk8k_test" ) == 0 ) {
check_encoder_option(decode_only, "-silk8k_test");
mode_list = silk8_test;
nb_modes_in_list = 8;
args++;
} else if( strcmp( argv[ args ], "-silk12k_test" ) == 0 ) {
check_encoder_option(decode_only, "-silk12k_test");
mode_list = silk12_test;
nb_modes_in_list = 8;
args++;
} else if( strcmp( argv[ args ], "-silk16k_test" ) == 0 ) {
check_encoder_option(decode_only, "-silk16k_test");
mode_list = silk16_test;
nb_modes_in_list = 8;
args++;
} else if( strcmp( argv[ args ], "-hybrid24k_test" ) == 0 ) {
check_encoder_option(decode_only, "-hybrid24k_test");
mode_list = hybrid24_test;
nb_modes_in_list = 4;
args++;
} else if( strcmp( argv[ args ], "-hybrid48k_test" ) == 0 ) {
check_encoder_option(decode_only, "-hybrid48k_test");
mode_list = hybrid48_test;
nb_modes_in_list = 4;
args++;
} else if( strcmp( argv[ args ], "-celt_test" ) == 0 ) {
check_encoder_option(decode_only, "-celt_test");
mode_list = celt_test;
nb_modes_in_list = 32;
args++;
} else if( strcmp( argv[ args ], "-celt_hq_test" ) == 0 ) {
check_encoder_option(decode_only, "-celt_hq_test");
mode_list = celt_hq_test;
nb_modes_in_list = 4;
args++;
} else {
printf( "Error: unrecognized setting: %s\n\n", argv[ args ] );
print_usage( argv );
goto failure;
}
}
if (sweep_max)
sweep_min = bitrate_bps;
if (max_payload_bytes < 0 || max_payload_bytes > MAX_PACKET)
{
fprintf (stderr, "max_payload_bytes must be between 0 and %d\n",
MAX_PACKET);
goto failure;
}
inFile = argv[argc-2];
fin = fopen(inFile, "rb");
if (!fin)
{
fprintf (stderr, "Could not open input file %s\n", argv[argc-2]);
goto failure;
}
if (mode_list)
{
int size;
fseek(fin, 0, SEEK_END);
size = ftell(fin);
fprintf(stderr, "File size is %d bytes\n", size);
fseek(fin, 0, SEEK_SET);
mode_switch_time = size/sizeof(short)/channels/nb_modes_in_list;
fprintf(stderr, "Switching mode every %d samples\n", mode_switch_time);
}
outFile = argv[argc-1];
fout = fopen(outFile, "wb+");
if (!fout)
{
fprintf (stderr, "Could not open output file %s\n", argv[argc-1]);
goto failure;
}
if (!decode_only)
{
enc = opus_encoder_create(sampling_rate, channels, application, &err);
if (err != OPUS_OK)
{
fprintf(stderr, "Cannot create encoder: %s\n", opus_strerror(err));
goto failure;
}
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(bandwidth));
opus_encoder_ctl(enc, OPUS_SET_VBR(use_vbr));
opus_encoder_ctl(enc, OPUS_SET_VBR_CONSTRAINT(cvbr));
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(use_inbandfec));
opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(forcechannels));
opus_encoder_ctl(enc, OPUS_SET_DTX(use_dtx));
opus_encoder_ctl(enc, OPUS_SET_PACKET_LOSS_PERC(packet_loss_perc));
opus_encoder_ctl(enc, OPUS_GET_LOOKAHEAD(&skip));
opus_encoder_ctl(enc, OPUS_SET_LSB_DEPTH(16));
opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
}
if (!encode_only)
{
dec = opus_decoder_create(sampling_rate, channels, &err);
if (err != OPUS_OK)
{
fprintf(stderr, "Cannot create decoder: %s\n", opus_strerror(err));
goto failure;
}
}
switch(bandwidth)
{
case OPUS_BANDWIDTH_NARROWBAND:
bandwidth_string = "narrowband";
break;
case OPUS_BANDWIDTH_MEDIUMBAND:
bandwidth_string = "mediumband";
break;
case OPUS_BANDWIDTH_WIDEBAND:
bandwidth_string = "wideband";
break;
case OPUS_BANDWIDTH_SUPERWIDEBAND:
bandwidth_string = "superwideband";
break;
case OPUS_BANDWIDTH_FULLBAND:
bandwidth_string = "fullband";
break;
case OPUS_AUTO:
bandwidth_string = "auto bandwidth";
break;
default:
bandwidth_string = "unknown";
break;
}
if (decode_only)
fprintf(stderr, "Decoding with %ld Hz output (%d channels)\n",
(long)sampling_rate, channels);
else
fprintf(stderr, "Encoding %ld Hz input at %.3f kb/s "
"in %s with %d-sample frames.\n",
(long)sampling_rate, bitrate_bps*0.001,
bandwidth_string, frame_size);
in = (short*)malloc(max_frame_size*channels*sizeof(short));
out = (short*)malloc(max_frame_size*channels*sizeof(short));
/* We need to allocate for 16-bit PCM data, but we store it as unsigned char. */
fbytes = (unsigned char*)malloc(max_frame_size*channels*sizeof(short));
data[0] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char));
if ( use_inbandfec ) {
data[1] = (unsigned char*)calloc(max_payload_bytes,sizeof(unsigned char));
}
if(delayed_decision)
{
if (frame_size==sampling_rate/400)
variable_duration = OPUS_FRAMESIZE_2_5_MS;
else if (frame_size==sampling_rate/200)
variable_duration = OPUS_FRAMESIZE_5_MS;
else if (frame_size==sampling_rate/100)
variable_duration = OPUS_FRAMESIZE_10_MS;
else if (frame_size==sampling_rate/50)
variable_duration = OPUS_FRAMESIZE_20_MS;
else if (frame_size==sampling_rate/25)
variable_duration = OPUS_FRAMESIZE_40_MS;
else if (frame_size==3*sampling_rate/50)
variable_duration = OPUS_FRAMESIZE_60_MS;
else if (frame_size==4*sampling_rate/50)
variable_duration = OPUS_FRAMESIZE_80_MS;
else if (frame_size==5*sampling_rate/50)
variable_duration = OPUS_FRAMESIZE_100_MS;
else
variable_duration = OPUS_FRAMESIZE_120_MS;
opus_encoder_ctl(enc, OPUS_SET_EXPERT_FRAME_DURATION(variable_duration));
frame_size = 2*48000;
}
while (!stop)
{
if (delayed_celt)
{
frame_size = newsize;
delayed_celt = 0;
} else if (random_framesize && rand()%20==0)
{
newsize = rand()%6;
switch(newsize)
{
case 0: newsize=sampling_rate/400; break;
case 1: newsize=sampling_rate/200; break;
case 2: newsize=sampling_rate/100; break;
case 3: newsize=sampling_rate/50; break;
case 4: newsize=sampling_rate/25; break;
case 5: newsize=3*sampling_rate/50; break;
}
while (newsize < sampling_rate/25 && bitrate_bps-abs(sweep_bps) <= 3*12*sampling_rate/newsize)
newsize*=2;
if (newsize < sampling_rate/100 && frame_size >= sampling_rate/100)
{
opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(MODE_CELT_ONLY));
delayed_celt=1;
} else {
frame_size = newsize;
}
}
if (random_fec && rand()%30==0)
{
opus_encoder_ctl(enc, OPUS_SET_INBAND_FEC(rand()%4==0));
}
if (decode_only)
{
unsigned char ch[4];
num_read = fread(ch, 1, 4, fin);
if (num_read!=4)
break;
len[toggle] = char_to_int(ch);
if (len[toggle]>max_payload_bytes || len[toggle]<0)
{
fprintf(stderr, "Invalid payload length: %d\n",len[toggle]);
break;
}
num_read = fread(ch, 1, 4, fin);
if (num_read!=4)
break;
enc_final_range[toggle] = char_to_int(ch);
num_read = fread(data[toggle], 1, len[toggle], fin);
if (num_read!=(size_t)len[toggle])
{
fprintf(stderr, "Ran out of input, "
"expecting %d bytes got %d\n",
len[toggle],(int)num_read);
break;
}
} else {
int i;
if (mode_list!=NULL)
{
opus_encoder_ctl(enc, OPUS_SET_BANDWIDTH(mode_list[curr_mode][1]));
opus_encoder_ctl(enc, OPUS_SET_FORCE_MODE(mode_list[curr_mode][0]));
opus_encoder_ctl(enc, OPUS_SET_FORCE_CHANNELS(mode_list[curr_mode][3]));
frame_size = mode_list[curr_mode][2];
}
num_read = fread(fbytes, sizeof(short)*channels, frame_size-remaining, fin);
curr_read = (int)num_read;
tot_in += curr_read;
for(i=0;i<curr_read*channels;i++)
{
opus_int32 s;
s=fbytes[2*i+1]<<8|fbytes[2*i];
s=((s&0xFFFF)^0x8000)-0x8000;
in[i+remaining*channels]=s;
}
if (curr_read+remaining < frame_size)
{
for (i=(curr_read+remaining)*channels;i<frame_size*channels;i++)
in[i] = 0;
if (encode_only || decode_only)
stop = 1;
}
len[toggle] = opus_encode(enc, in, frame_size, data[toggle], max_payload_bytes);
nb_encoded = opus_packet_get_samples_per_frame(data[toggle], sampling_rate)*opus_packet_get_nb_frames(data[toggle], len[toggle]);
remaining = frame_size-nb_encoded;
for(i=0;i<remaining*channels;i++)
in[i] = in[nb_encoded*channels+i];
if (sweep_bps!=0)
{
bitrate_bps += sweep_bps;
if (sweep_max)
{
if (bitrate_bps > sweep_max)
sweep_bps = -sweep_bps;
else if (bitrate_bps < sweep_min)
sweep_bps = -sweep_bps;
}
/* safety */
if (bitrate_bps<1000)
bitrate_bps = 1000;
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate_bps));
}
opus_encoder_ctl(enc, OPUS_GET_FINAL_RANGE(&enc_final_range[toggle]));
if (len[toggle] < 0)
{
fprintf (stderr, "opus_encode() returned %d\n", len[toggle]);
goto failure;
}
curr_mode_count += frame_size;
if (curr_mode_count > mode_switch_time && curr_mode < nb_modes_in_list-1)
{
curr_mode++;
curr_mode_count = 0;
}
}
#if 0 /* This is for testing the padding code, do not enable by default */
if (len[toggle]<1275)
{
int new_len = len[toggle]+rand()%(max_payload_bytes-len[toggle]);
if ((err = opus_packet_pad(data[toggle], len[toggle], new_len)) != OPUS_OK)
{
fprintf(stderr, "padding failed: %s\n", opus_strerror(err));
goto failure;
}
len[toggle] = new_len;
}
#endif
if (encode_only)
{
unsigned char int_field[4];
int_to_char(len[toggle], int_field);
if (fwrite(int_field, 1, 4, fout) != 4) {
fprintf(stderr, "Error writing.\n");
goto failure;
}
int_to_char(enc_final_range[toggle], int_field);
if (fwrite(int_field, 1, 4, fout) != 4) {
fprintf(stderr, "Error writing.\n");
goto failure;
}
if (fwrite(data[toggle], 1, len[toggle], fout) != (unsigned)len[toggle]) {
fprintf(stderr, "Error writing.\n");
goto failure;
}
tot_samples += nb_encoded;
} else {
opus_int32 output_samples;
lost = len[toggle]==0 || (packet_loss_perc>0 && rand()%100 < packet_loss_perc);
if (lost)
opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
else
output_samples = max_frame_size;
if( count >= use_inbandfec ) {
/* delay by one packet when using in-band FEC */
if( use_inbandfec ) {
if( lost_prev ) {
/* attempt to decode with in-band FEC from next packet */
opus_decoder_ctl(dec, OPUS_GET_LAST_PACKET_DURATION(&output_samples));
output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 1);
} else {
/* regular decode */
output_samples = max_frame_size;
output_samples = opus_decode(dec, data[1-toggle], len[1-toggle], out, output_samples, 0);
}
} else {
output_samples = opus_decode(dec, lost ? NULL : data[toggle], len[toggle], out, output_samples, 0);
}
if (output_samples>0)
{
if (!decode_only && tot_out + output_samples > tot_in)
{
stop=1;
output_samples = (opus_int32)(tot_in - tot_out);
}
if (output_samples>skip) {
int i;
for(i=0;i<(output_samples-skip)*channels;i++)
{
short s;
s=out[i+(skip*channels)];
fbytes[2*i]=s&0xFF;
fbytes[2*i+1]=(s>>8)&0xFF;
}
if (fwrite(fbytes, sizeof(short)*channels, output_samples-skip, fout) != (unsigned)(output_samples-skip)){
fprintf(stderr, "Error writing.\n");
goto failure;
}
tot_out += output_samples-skip;
}
if (output_samples<skip) skip -= output_samples;
else skip = 0;
} else {
fprintf(stderr, "error decoding frame: %s\n",
opus_strerror(output_samples));
}
tot_samples += output_samples;
}
}
if (!encode_only)
opus_decoder_ctl(dec, OPUS_GET_FINAL_RANGE(&dec_final_range));
/* compare final range encoder rng values of encoder and decoder */
if( enc_final_range[toggle^use_inbandfec]!=0 && !encode_only
&& !lost && !lost_prev
&& dec_final_range != enc_final_range[toggle^use_inbandfec] ) {
fprintf (stderr, "Error: Range coder state mismatch "
"between encoder and decoder "
"in frame %ld: 0x%8lx vs 0x%8lx\n",
(long)count,
(unsigned long)enc_final_range[toggle^use_inbandfec],
(unsigned long)dec_final_range);
goto failure;
}
lost_prev = lost;
if( count >= use_inbandfec ) {
/* count bits */
bits += len[toggle]*8;
bits_max = ( len[toggle]*8 > bits_max ) ? len[toggle]*8 : bits_max;
bits2 += len[toggle]*len[toggle]*64;
if (!decode_only)
{
nrg = 0.0;
for ( k = 0; k < frame_size * channels; k++ ) {
nrg += in[ k ] * (double)in[ k ];
}
nrg /= frame_size * channels;
if( nrg > 1e5 ) {
bits_act += len[toggle]*8;
count_act++;
}
}
}
count++;
toggle = (toggle + use_inbandfec) & 1;
}
if(decode_only && count > 0)
frame_size = (int)(tot_samples / count);
count -= use_inbandfec;
if (tot_samples >= 1 && count > 0 && frame_size)
{
/* Print out bitrate statistics */
double var;
fprintf (stderr, "average bitrate: %7.3f kb/s\n",
1e-3*bits*sampling_rate/tot_samples);
fprintf (stderr, "maximum bitrate: %7.3f kb/s\n",
1e-3*bits_max*sampling_rate/frame_size);
if (!decode_only)
fprintf (stderr, "active bitrate: %7.3f kb/s\n",
1e-3*bits_act*sampling_rate/(1e-15+frame_size*(double)count_act));
var = bits2/count - bits*bits/(count*(double)count);
if (var < 0)
var = 0;
fprintf (stderr, "bitrate standard deviation: %7.3f kb/s\n",
1e-3*sqrt(var)*sampling_rate/frame_size);
} else {
fprintf(stderr, "bitrate statistics are undefined\n");
}
silk_TimerSave("opus_timing.txt");
ret = EXIT_SUCCESS;
failure:
opus_encoder_destroy(enc);
opus_decoder_destroy(dec);
free(data[0]);
free(data[1]);
if (fin)
fclose(fin);
if (fout)
fclose(fout);
free(in);
free(out);
free(fbytes);
return ret;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,92 @@
/* Copyright (c) 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
#include "opus_multistream.h"
#include "opus.h"
#include "opus_private.h"
#include "stack_alloc.h"
#include <stdarg.h>
#include "float_cast.h"
#include "os_support.h"
int validate_layout(const ChannelLayout *layout)
{
int i, max_channel;
max_channel = layout->nb_streams+layout->nb_coupled_streams;
if (max_channel>255)
return 0;
for (i=0;i<layout->nb_channels;i++)
{
if (layout->mapping[i] >= max_channel && layout->mapping[i] != 255)
return 0;
}
return 1;
}
int get_left_channel(const ChannelLayout *layout, int stream_id, int prev)
{
int i;
i = (prev<0) ? 0 : prev+1;
for (;i<layout->nb_channels;i++)
{
if (layout->mapping[i]==stream_id*2)
return i;
}
return -1;
}
int get_right_channel(const ChannelLayout *layout, int stream_id, int prev)
{
int i;
i = (prev<0) ? 0 : prev+1;
for (;i<layout->nb_channels;i++)
{
if (layout->mapping[i]==stream_id*2+1)
return i;
}
return -1;
}
int get_mono_channel(const ChannelLayout *layout, int stream_id, int prev)
{
int i;
i = (prev<0) ? 0 : prev+1;
for (;i<layout->nb_channels;i++)
{
if (layout->mapping[i]==stream_id+layout->nb_coupled_streams)
return i;
}
return -1;
}

View file

@ -0,0 +1,549 @@
/* Copyright (c) 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
#include "opus_multistream.h"
#include "opus.h"
#include "opus_private.h"
#include "stack_alloc.h"
#include <stdarg.h>
#include "float_cast.h"
#include "os_support.h"
/* 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;
int mono_size;
if(nb_streams<1||nb_coupled_streams>nb_streams||nb_coupled_streams<0)return 0;
coupled_size = opus_decoder_get_size(2);
mono_size = opus_decoder_get_size(1);
return align(sizeof(OpusMSDecoder))
+ nb_coupled_streams * align(coupled_size)
+ (nb_streams-nb_coupled_streams) * align(mono_size);
}
int opus_multistream_decoder_init(
OpusMSDecoder *st,
opus_int32 Fs,
int channels,
int streams,
int coupled_streams,
const unsigned char *mapping
)
{
int coupled_size;
int mono_size;
int i, ret;
char *ptr;
if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
(streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
return OPUS_BAD_ARG;
st->layout.nb_channels = channels;
st->layout.nb_streams = streams;
st->layout.nb_coupled_streams = coupled_streams;
for (i=0;i<st->layout.nb_channels;i++)
st->layout.mapping[i] = mapping[i];
if (!validate_layout(&st->layout))
return OPUS_BAD_ARG;
ptr = (char*)st + align(sizeof(OpusMSDecoder));
coupled_size = opus_decoder_get_size(2);
mono_size = opus_decoder_get_size(1);
for (i=0;i<st->layout.nb_coupled_streams;i++)
{
ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 2);
if(ret!=OPUS_OK)return ret;
ptr += align(coupled_size);
}
for (;i<st->layout.nb_streams;i++)
{
ret=opus_decoder_init((OpusDecoder*)ptr, Fs, 1);
if(ret!=OPUS_OK)return ret;
ptr += align(mono_size);
}
return OPUS_OK;
}
OpusMSDecoder *opus_multistream_decoder_create(
opus_int32 Fs,
int channels,
int streams,
int coupled_streams,
const unsigned char *mapping,
int *error
)
{
int ret;
OpusMSDecoder *st;
if ((channels>255) || (channels<1) || (coupled_streams>streams) ||
(streams<1) || (coupled_streams<0) || (streams>255-coupled_streams))
{
if (error)
*error = OPUS_BAD_ARG;
return NULL;
}
st = (OpusMSDecoder *)opus_alloc(opus_multistream_decoder_get_size(streams, coupled_streams));
if (st==NULL)
{
if (error)
*error = OPUS_ALLOC_FAIL;
return NULL;
}
ret = opus_multistream_decoder_init(st, Fs, channels, streams, coupled_streams, mapping);
if (error)
*error = ret;
if (ret != OPUS_OK)
{
opus_free(st);
st = NULL;
}
return st;
}
static int opus_multistream_packet_validate(const unsigned char *data,
opus_int32 len, int nb_streams, opus_int32 Fs)
{
int s;
int count;
unsigned char toc;
opus_int16 size[48];
int samples=0;
opus_int32 packet_offset;
for (s=0;s<nb_streams;s++)
{
int tmp_samples;
if (len<=0)
return OPUS_INVALID_PACKET;
count = opus_packet_parse_impl(data, len, s!=nb_streams-1, &toc, NULL,
size, NULL, &packet_offset);
if (count<0)
return count;
tmp_samples = opus_packet_get_nb_samples(data, packet_offset, Fs);
if (s!=0 && samples != tmp_samples)
return OPUS_INVALID_PACKET;
samples = tmp_samples;
data += packet_offset;
len -= packet_offset;
}
return samples;
}
int opus_multistream_decode_native(
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
)
{
opus_int32 Fs;
int coupled_size;
int mono_size;
int s, c;
char *ptr;
int do_plc=0;
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. */
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));
coupled_size = opus_decoder_get_size(2);
mono_size = opus_decoder_get_size(1);
if (len==0)
do_plc = 1;
if (len < 0)
{
RESTORE_STACK;
return OPUS_BAD_ARG;
}
if (!do_plc && len < 2*st->layout.nb_streams-1)
{
RESTORE_STACK;
return OPUS_INVALID_PACKET;
}
if (!do_plc)
{
int ret = opus_multistream_packet_validate(data, len, st->layout.nb_streams, Fs);
if (ret < 0)
{
RESTORE_STACK;
return ret;
} else if (ret > frame_size)
{
RESTORE_STACK;
return OPUS_BUFFER_TOO_SMALL;
}
}
for (s=0;s<st->layout.nb_streams;s++)
{
OpusDecoder *dec;
opus_int32 packet_offset;
int ret;
dec = (OpusDecoder*)ptr;
ptr += (s < st->layout.nb_coupled_streams) ? align(coupled_size) : align(mono_size);
if (!do_plc && len<=0)
{
RESTORE_STACK;
return OPUS_INTERNAL_ERROR;
}
packet_offset = 0;
ret = opus_decode_native(dec, data, len, buf, frame_size, decode_fec, s!=st->layout.nb_streams-1, &packet_offset, soft_clip);
data += packet_offset;
len -= packet_offset;
if (ret <= 0)
{
RESTORE_STACK;
return ret;
}
frame_size = ret;
if (s < st->layout.nb_coupled_streams)
{
int chan, prev;
prev = -1;
/* Copy "left" audio to the channel(s) where it belongs */
while ( (chan = get_left_channel(&st->layout, s, prev)) != -1)
{
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
buf, 2, frame_size, user_data);
prev = chan;
}
prev = -1;
/* Copy "right" audio to the channel(s) where it belongs */
while ( (chan = get_right_channel(&st->layout, s, prev)) != -1)
{
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
buf+1, 2, frame_size, user_data);
prev = chan;
}
} else {
int chan, prev;
prev = -1;
/* Copy audio to the channel(s) where it belongs */
while ( (chan = get_mono_channel(&st->layout, s, prev)) != -1)
{
(*copy_channel_out)(pcm, st->layout.nb_channels, chan,
buf, 1, frame_size, user_data);
prev = chan;
}
}
}
/* Handle muted channels */
for (c=0;c<st->layout.nb_channels;c++)
{
if (st->layout.mapping[c] == 255)
{
(*copy_channel_out)(pcm, st->layout.nb_channels, c,
NULL, 0, frame_size, user_data);
}
}
RESTORE_STACK;
return frame_size;
}
#if !defined(DISABLE_FLOAT_API)
static void opus_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;
opus_int32 i;
(void)user_data;
float_dst = (float*)dst;
if (src != NULL)
{
for (i=0;i<frame_size;i++)
#if defined(FIXED_POINT)
float_dst[i*dst_stride+dst_channel] = (1/32768.f)*src[i*src_stride];
#else
float_dst[i*dst_stride+dst_channel] = src[i*src_stride];
#endif
}
else
{
for (i=0;i<frame_size;i++)
float_dst[i*dst_stride+dst_channel] = 0;
}
}
#endif
static void opus_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;
opus_int32 i;
(void)user_data;
short_dst = (opus_int16*)dst;
if (src != NULL)
{
for (i=0;i<frame_size;i++)
#if defined(FIXED_POINT)
short_dst[i*dst_stride+dst_channel] = src[i*src_stride];
#else
short_dst[i*dst_stride+dst_channel] = FLOAT2INT16(src[i*src_stride]);
#endif
}
else
{
for (i=0;i<frame_size;i++)
short_dst[i*dst_stride+dst_channel] = 0;
}
}
#ifdef FIXED_POINT
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, 0, NULL);
}
#ifndef DISABLE_FLOAT_API
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, NULL);
}
#endif
#else
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, NULL);
}
int opus_multistream_decode_float(
OpusMSDecoder *st,
const unsigned char *data,
opus_int32 len,
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, NULL);
}
#endif
int opus_multistream_decoder_ctl_va_list(OpusMSDecoder *st, int request,
va_list ap)
{
int coupled_size, mono_size;
char *ptr;
int ret = OPUS_OK;
coupled_size = opus_decoder_get_size(2);
mono_size = opus_decoder_get_size(1);
ptr = (char*)st + align(sizeof(OpusMSDecoder));
switch (request)
{
case OPUS_GET_BANDWIDTH_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 */
opus_int32 *value = va_arg(ap, opus_int32*);
dec = (OpusDecoder*)ptr;
ret = opus_decoder_ctl(dec, request, value);
}
break;
case OPUS_GET_FINAL_RANGE_REQUEST:
{
int s;
opus_uint32 *value = va_arg(ap, opus_uint32*);
opus_uint32 tmp;
if (!value)
{
goto bad_arg;
}
*value = 0;
for (s=0;s<st->layout.nb_streams;s++)
{
OpusDecoder *dec;
dec = (OpusDecoder*)ptr;
if (s < st->layout.nb_coupled_streams)
ptr += align(coupled_size);
else
ptr += align(mono_size);
ret = opus_decoder_ctl(dec, request, &tmp);
if (ret != OPUS_OK) break;
*value ^= tmp;
}
}
break;
case OPUS_RESET_STATE:
{
int s;
for (s=0;s<st->layout.nb_streams;s++)
{
OpusDecoder *dec;
dec = (OpusDecoder*)ptr;
if (s < st->layout.nb_coupled_streams)
ptr += align(coupled_size);
else
ptr += align(mono_size);
ret = opus_decoder_ctl(dec, OPUS_RESET_STATE);
if (ret != OPUS_OK)
break;
}
}
break;
case OPUS_MULTISTREAM_GET_DECODER_STATE_REQUEST:
{
int s;
opus_int32 stream_id;
OpusDecoder **value;
stream_id = va_arg(ap, opus_int32);
if (stream_id<0 || stream_id >= st->layout.nb_streams)
goto bad_arg;
value = va_arg(ap, OpusDecoder**);
if (!value)
{
goto bad_arg;
}
for (s=0;s<stream_id;s++)
{
if (s < st->layout.nb_coupled_streams)
ptr += align(coupled_size);
else
ptr += align(mono_size);
}
*value = (OpusDecoder*)ptr;
}
break;
case OPUS_SET_GAIN_REQUEST:
case OPUS_SET_PHASE_INVERSION_DISABLED_REQUEST:
{
int s;
/* This works for int32 params */
opus_int32 value = va_arg(ap, opus_int32);
for (s=0;s<st->layout.nb_streams;s++)
{
OpusDecoder *dec;
dec = (OpusDecoder*)ptr;
if (s < st->layout.nb_coupled_streams)
ptr += align(coupled_size);
else
ptr += align(mono_size);
ret = opus_decoder_ctl(dec, request, value);
if (ret != OPUS_OK)
break;
}
}
break;
default:
ret = OPUS_UNIMPLEMENTED;
break;
}
return ret;
bad_arg:
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)
{
opus_free(st);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
/* Copyright (c) 2012 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.
*/
#ifndef OPUS_PRIVATE_H
#define OPUS_PRIVATE_H
#include "arch.h"
#include "opus.h"
#include "celt.h"
#include <stdarg.h> /* va_list */
#include <stddef.h> /* offsetof */
struct OpusRepacketizer {
unsigned char toc;
int nb_frames;
const unsigned char *frames[48];
opus_int16 len[48];
int framesize;
};
typedef struct ChannelLayout {
int nb_channels;
int nb_streams;
int nb_coupled_streams;
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
#define MODE_CELT_ONLY 1002
#define OPUS_SET_VOICE_RATIO_REQUEST 11018
#define OPUS_GET_VOICE_RATIO_REQUEST 11019
/** Configures the encoder's expected percentage of voice
* opposed to music or other signals.
*
* @note This interface is currently more aspiration than actuality. It's
* ultimately expected to bias an automatic signal classifier, but it currently
* just shifts the static bitrate to mode mapping around a little bit.
*
* @param[in] x <tt>int</tt>: Voice percentage in the range 0-100, inclusive.
* @hideinitializer */
#define OPUS_SET_VOICE_RATIO(x) OPUS_SET_VOICE_RATIO_REQUEST, __opus_check_int(x)
/** Gets the encoder's configured voice ratio value, @see OPUS_SET_VOICE_RATIO
*
* @param[out] x <tt>int*</tt>: Voice percentage in the range 0-100, inclusive.
* @hideinitializer */
#define OPUS_GET_VOICE_RATIO(x) OPUS_GET_VOICE_RATIO_REQUEST, __opus_check_int_ptr(x)
#define OPUS_SET_FORCE_MODE_REQUEST 11002
#define OPUS_SET_FORCE_MODE(x) OPUS_SET_FORCE_MODE_REQUEST, __opus_check_int(x)
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 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,
int analysis_channels, downmix_func downmix, int float_api);
int opus_decode_native(OpusDecoder *st, const unsigned char *data, opus_int32 len,
opus_val16 *pcm, int frame_size, int decode_fec, int self_delimited,
opus_int32 *packet_offset, int soft_clip);
/* Make sure everything is properly aligned. */
static OPUS_INLINE int align(int i)
{
struct foo {char c; union { void* p; opus_int32 i; opus_val32 v; } u;};
unsigned int alignment = offsetof(struct foo, u);
/* Optimizing compilers should optimize div and multiply into and
for all sensible alignment values. */
return ((i + alignment - 1) / alignment) * alignment;
}
int opus_packet_parse_impl(const unsigned char *data, opus_int32 len,
int self_delimited, unsigned char *out_toc,
const unsigned char *frames[48], opus_int16 size[48],
int *payload_offset, opus_int32 *packet_offset);
opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
unsigned char *data, opus_int32 maxlen, int self_delimited, int pad);
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 */

View file

@ -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);
}

View file

@ -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;
}

View file

@ -0,0 +1,349 @@
/* Copyright (c) 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
#include "opus.h"
#include "opus_private.h"
#include "os_support.h"
int opus_repacketizer_get_size(void)
{
return sizeof(OpusRepacketizer);
}
OpusRepacketizer *opus_repacketizer_init(OpusRepacketizer *rp)
{
rp->nb_frames = 0;
return rp;
}
OpusRepacketizer *opus_repacketizer_create(void)
{
OpusRepacketizer *rp;
rp=(OpusRepacketizer *)opus_alloc(opus_repacketizer_get_size());
if(rp==NULL)return NULL;
return opus_repacketizer_init(rp);
}
void opus_repacketizer_destroy(OpusRepacketizer *rp)
{
opus_free(rp);
}
static int opus_repacketizer_cat_impl(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len, int self_delimited)
{
unsigned char tmp_toc;
int curr_nb_frames,ret;
/* Set of check ToC */
if (len<1) return OPUS_INVALID_PACKET;
if (rp->nb_frames == 0)
{
rp->toc = data[0];
rp->framesize = opus_packet_get_samples_per_frame(data, 8000);
} else if ((rp->toc&0xFC) != (data[0]&0xFC))
{
/*fprintf(stderr, "toc mismatch: 0x%x vs 0x%x\n", rp->toc, data[0]);*/
return OPUS_INVALID_PACKET;
}
curr_nb_frames = opus_packet_get_nb_frames(data, len);
if(curr_nb_frames<1) return OPUS_INVALID_PACKET;
/* Check the 120 ms maximum packet size */
if ((curr_nb_frames+rp->nb_frames)*rp->framesize > 960)
{
return OPUS_INVALID_PACKET;
}
ret=opus_packet_parse_impl(data, len, self_delimited, &tmp_toc, &rp->frames[rp->nb_frames], &rp->len[rp->nb_frames], NULL, NULL);
if(ret<1)return ret;
rp->nb_frames += curr_nb_frames;
return OPUS_OK;
}
int opus_repacketizer_cat(OpusRepacketizer *rp, const unsigned char *data, opus_int32 len)
{
return opus_repacketizer_cat_impl(rp, data, len, 0);
}
int opus_repacketizer_get_nb_frames(OpusRepacketizer *rp)
{
return rp->nb_frames;
}
opus_int32 opus_repacketizer_out_range_impl(OpusRepacketizer *rp, int begin, int end,
unsigned char *data, opus_int32 maxlen, int self_delimited, int pad)
{
int i, count;
opus_int32 tot_size;
opus_int16 *len;
const unsigned char **frames;
unsigned char * ptr;
if (begin<0 || begin>=end || end>rp->nb_frames)
{
/*fprintf(stderr, "%d %d %d\n", begin, end, rp->nb_frames);*/
return OPUS_BAD_ARG;
}
count = end-begin;
len = rp->len+begin;
frames = rp->frames+begin;
if (self_delimited)
tot_size = 1 + (len[count-1]>=252);
else
tot_size = 0;
ptr = data;
if (count==1)
{
/* Code 0 */
tot_size += len[0]+1;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*ptr++ = rp->toc&0xFC;
} else if (count==2)
{
if (len[1] == len[0])
{
/* Code 1 */
tot_size += 2*len[0]+1;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*ptr++ = (rp->toc&0xFC) | 0x1;
} else {
/* Code 2 */
tot_size += len[0]+len[1]+2+(len[0]>=252);
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*ptr++ = (rp->toc&0xFC) | 0x2;
ptr += encode_size(len[0], ptr);
}
}
if (count > 2 || (pad && tot_size < maxlen))
{
/* Code 3 */
int vbr;
int pad_amount=0;
/* Restart the process for the padding case */
ptr = data;
if (self_delimited)
tot_size = 1 + (len[count-1]>=252);
else
tot_size = 0;
vbr = 0;
for (i=1;i<count;i++)
{
if (len[i] != len[0])
{
vbr=1;
break;
}
}
if (vbr)
{
tot_size += 2;
for (i=0;i<count-1;i++)
tot_size += 1 + (len[i]>=252) + len[i];
tot_size += len[count-1];
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*ptr++ = (rp->toc&0xFC) | 0x3;
*ptr++ = count | 0x80;
} else {
tot_size += count*len[0]+2;
if (tot_size > maxlen)
return OPUS_BUFFER_TOO_SMALL;
*ptr++ = (rp->toc&0xFC) | 0x3;
*ptr++ = count;
}
pad_amount = pad ? (maxlen-tot_size) : 0;
if (pad_amount != 0)
{
int nb_255s;
data[1] |= 0x40;
nb_255s = (pad_amount-1)/255;
for (i=0;i<nb_255s;i++)
*ptr++ = 255;
*ptr++ = pad_amount-255*nb_255s-1;
tot_size += pad_amount;
}
if (vbr)
{
for (i=0;i<count-1;i++)
ptr += encode_size(len[i], ptr);
}
}
if (self_delimited) {
int sdlen = encode_size(len[count-1], ptr);
ptr += sdlen;
}
/* Copy the actual data */
for (i=0;i<count;i++)
{
/* Using OPUS_MOVE() instead of OPUS_COPY() in case we're doing in-place
padding from opus_packet_pad or opus_packet_unpad(). */
/* 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];
}
if (pad)
{
/* Fill padding with zeros. */
while (ptr<data+maxlen)
*ptr++=0;
}
return tot_size;
}
opus_int32 opus_repacketizer_out_range(OpusRepacketizer *rp, int begin, int end, unsigned char *data, opus_int32 maxlen)
{
return opus_repacketizer_out_range_impl(rp, begin, end, data, maxlen, 0, 0);
}
opus_int32 opus_repacketizer_out(OpusRepacketizer *rp, unsigned char *data, opus_int32 maxlen)
{
return opus_repacketizer_out_range_impl(rp, 0, rp->nb_frames, data, maxlen, 0, 0);
}
int opus_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len)
{
OpusRepacketizer rp;
opus_int32 ret;
if (len < 1)
return OPUS_BAD_ARG;
if (len==new_len)
return OPUS_OK;
else if (len > new_len)
return OPUS_BAD_ARG;
opus_repacketizer_init(&rp);
/* Moving payload to the end of the packet so we can do in-place padding */
OPUS_MOVE(data+new_len-len, data, len);
ret = opus_repacketizer_cat(&rp, data+new_len-len, len);
if (ret != OPUS_OK)
return ret;
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, new_len, 0, 1);
if (ret > 0)
return OPUS_OK;
else
return ret;
}
opus_int32 opus_packet_unpad(unsigned char *data, opus_int32 len)
{
OpusRepacketizer rp;
opus_int32 ret;
if (len < 1)
return OPUS_BAD_ARG;
opus_repacketizer_init(&rp);
ret = opus_repacketizer_cat(&rp, data, len);
if (ret < 0)
return ret;
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, data, len, 0, 0);
celt_assert(ret > 0 && ret <= len);
return ret;
}
int opus_multistream_packet_pad(unsigned char *data, opus_int32 len, opus_int32 new_len, int nb_streams)
{
int s;
int count;
unsigned char toc;
opus_int16 size[48];
opus_int32 packet_offset;
opus_int32 amount;
if (len < 1)
return OPUS_BAD_ARG;
if (len==new_len)
return OPUS_OK;
else if (len > new_len)
return OPUS_BAD_ARG;
amount = new_len - len;
/* Seek to last stream */
for (s=0;s<nb_streams-1;s++)
{
if (len<=0)
return OPUS_INVALID_PACKET;
count = opus_packet_parse_impl(data, len, 1, &toc, NULL,
size, NULL, &packet_offset);
if (count<0)
return count;
data += packet_offset;
len -= packet_offset;
}
return opus_packet_pad(data, len, len+amount);
}
opus_int32 opus_multistream_packet_unpad(unsigned char *data, opus_int32 len, int nb_streams)
{
int s;
unsigned char toc;
opus_int16 size[48];
opus_int32 packet_offset;
OpusRepacketizer rp;
unsigned char *dst;
opus_int32 dst_len;
if (len < 1)
return OPUS_BAD_ARG;
dst = data;
dst_len = 0;
/* Unpad all frames */
for (s=0;s<nb_streams;s++)
{
opus_int32 ret;
int self_delimited = s!=nb_streams-1;
if (len<=0)
return OPUS_INVALID_PACKET;
opus_repacketizer_init(&rp);
ret = opus_packet_parse_impl(data, len, self_delimited, &toc, NULL,
size, NULL, &packet_offset);
if (ret<0)
return ret;
ret = opus_repacketizer_cat_impl(&rp, data, packet_offset, self_delimited);
if (ret < 0)
return ret;
ret = opus_repacketizer_out_range_impl(&rp, 0, rp.nb_frames, dst, len, self_delimited, 0);
if (ret < 0)
return ret;
else
dst_len += ret;
dst += ret;
data += packet_offset;
len -= packet_offset;
}
return dst_len;
}

View file

@ -0,0 +1,217 @@
/* Copyright (c) 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
#include "opus.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_PACKETOUT 32000
void usage(char *argv0)
{
fprintf(stderr, "usage: %s [options] input_file output_file\n", argv0);
}
static void int_to_char(opus_uint32 i, unsigned char ch[4])
{
ch[0] = i>>24;
ch[1] = (i>>16)&0xFF;
ch[2] = (i>>8)&0xFF;
ch[3] = i&0xFF;
}
static opus_uint32 char_to_int(unsigned char ch[4])
{
return ((opus_uint32)ch[0]<<24) | ((opus_uint32)ch[1]<<16)
| ((opus_uint32)ch[2]<< 8) | (opus_uint32)ch[3];
}
int main(int argc, char *argv[])
{
int i, eof=0;
FILE *fin, *fout;
unsigned char packets[48][1500];
int len[48];
int rng[48];
OpusRepacketizer *rp;
unsigned char output_packet[MAX_PACKETOUT];
int merge = 1, split=0;
if (argc < 3)
{
usage(argv[0]);
return EXIT_FAILURE;
}
for (i=1;i<argc-2;i++)
{
if (strcmp(argv[i], "-merge")==0)
{
merge = atoi(argv[i+1]);
if(merge<1)
{
fprintf(stderr, "-merge parameter must be at least 1.\n");
return EXIT_FAILURE;
}
if(merge>48)
{
fprintf(stderr, "-merge parameter must be less than 48.\n");
return EXIT_FAILURE;
}
i++;
} else if (strcmp(argv[i], "-split")==0)
split = 1;
else
{
fprintf(stderr, "Unknown option: %s\n", argv[i]);
usage(argv[0]);
return EXIT_FAILURE;
}
}
fin = fopen(argv[argc-2], "r");
if(fin==NULL)
{
fprintf(stderr, "Error opening input file: %s\n", argv[argc-2]);
return EXIT_FAILURE;
}
fout = fopen(argv[argc-1], "w");
if(fout==NULL)
{
fprintf(stderr, "Error opening output file: %s\n", argv[argc-1]);
fclose(fin);
return EXIT_FAILURE;
}
rp = opus_repacketizer_create();
while (!eof)
{
int err;
int nb_packets=merge;
opus_repacketizer_init(rp);
for (i=0;i<nb_packets;i++)
{
unsigned char ch[4];
err = fread(ch, 1, 4, fin);
len[i] = char_to_int(ch);
/*fprintf(stderr, "in len = %d\n", len[i]);*/
if (len[i]>1500 || len[i]<0)
{
if (feof(fin))
{
eof = 1;
} else {
fprintf(stderr, "Invalid payload length\n");
fclose(fin);
fclose(fout);
return EXIT_FAILURE;
}
break;
}
err = fread(ch, 1, 4, fin);
rng[i] = char_to_int(ch);
err = fread(packets[i], 1, len[i], fin);
if (feof(fin))
{
eof = 1;
break;
}
err = opus_repacketizer_cat(rp, packets[i], len[i]);
if (err!=OPUS_OK)
{
fprintf(stderr, "opus_repacketizer_cat() failed: %s\n", opus_strerror(err));
break;
}
}
nb_packets = i;
if (eof)
break;
if (!split)
{
err = opus_repacketizer_out(rp, output_packet, MAX_PACKETOUT);
if (err>0) {
unsigned char int_field[4];
int_to_char(err, int_field);
if(fwrite(int_field, 1, 4, fout)!=4){
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
int_to_char(rng[nb_packets-1], int_field);
if (fwrite(int_field, 1, 4, fout)!=4) {
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
/*fprintf(stderr, "out len = %d\n", err);*/
} else {
fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
}
} else {
int nb_frames = opus_repacketizer_get_nb_frames(rp);
for (i=0;i<nb_frames;i++)
{
err = opus_repacketizer_out_range(rp, i, i+1, output_packet, MAX_PACKETOUT);
if (err>0) {
unsigned char int_field[4];
int_to_char(err, int_field);
if (fwrite(int_field, 1, 4, fout)!=4) {
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
if (i==nb_frames-1)
int_to_char(rng[nb_packets-1], int_field);
else
int_to_char(0, int_field);
if (fwrite(int_field, 1, 4, fout)!=4) {
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
if (fwrite(output_packet, 1, err, fout)!=(unsigned)err) {
fprintf(stderr, "Error writing.\n");
return EXIT_FAILURE;
}
/*fprintf(stderr, "out len = %d\n", err);*/
} else {
fprintf(stderr, "opus_repacketizer_out() failed: %s\n", opus_strerror(err));
}
}
}
}
fclose(fin);
fclose(fout);
return EXIT_SUCCESS;
}

View file

@ -0,0 +1,45 @@
/* This file is auto-generated by gen_tables */
static const float tansig_table[201] = {
0.000000f, 0.039979f, 0.079830f, 0.119427f, 0.158649f,
0.197375f, 0.235496f, 0.272905f, 0.309507f, 0.345214f,
0.379949f, 0.413644f, 0.446244f, 0.477700f, 0.507977f,
0.537050f, 0.564900f, 0.591519f, 0.616909f, 0.641077f,
0.664037f, 0.685809f, 0.706419f, 0.725897f, 0.744277f,
0.761594f, 0.777888f, 0.793199f, 0.807569f, 0.821040f,
0.833655f, 0.845456f, 0.856485f, 0.866784f, 0.876393f,
0.885352f, 0.893698f, 0.901468f, 0.908698f, 0.915420f,
0.921669f, 0.927473f, 0.932862f, 0.937863f, 0.942503f,
0.946806f, 0.950795f, 0.954492f, 0.957917f, 0.961090f,
0.964028f, 0.966747f, 0.969265f, 0.971594f, 0.973749f,
0.975743f, 0.977587f, 0.979293f, 0.980869f, 0.982327f,
0.983675f, 0.984921f, 0.986072f, 0.987136f, 0.988119f,
0.989027f, 0.989867f, 0.990642f, 0.991359f, 0.992020f,
0.992631f, 0.993196f, 0.993718f, 0.994199f, 0.994644f,
0.995055f, 0.995434f, 0.995784f, 0.996108f, 0.996407f,
0.996682f, 0.996937f, 0.997172f, 0.997389f, 0.997590f,
0.997775f, 0.997946f, 0.998104f, 0.998249f, 0.998384f,
0.998508f, 0.998623f, 0.998728f, 0.998826f, 0.998916f,
0.999000f, 0.999076f, 0.999147f, 0.999213f, 0.999273f,
0.999329f, 0.999381f, 0.999428f, 0.999472f, 0.999513f,
0.999550f, 0.999585f, 0.999617f, 0.999646f, 0.999673f,
0.999699f, 0.999722f, 0.999743f, 0.999763f, 0.999781f,
0.999798f, 0.999813f, 0.999828f, 0.999841f, 0.999853f,
0.999865f, 0.999875f, 0.999885f, 0.999893f, 0.999902f,
0.999909f, 0.999916f, 0.999923f, 0.999929f, 0.999934f,
0.999939f, 0.999944f, 0.999948f, 0.999952f, 0.999956f,
0.999959f, 0.999962f, 0.999965f, 0.999968f, 0.999970f,
0.999973f, 0.999975f, 0.999977f, 0.999978f, 0.999980f,
0.999982f, 0.999983f, 0.999984f, 0.999986f, 0.999987f,
0.999988f, 0.999989f, 0.999990f, 0.999990f, 0.999991f,
0.999992f, 0.999992f, 0.999993f, 0.999994f, 0.999994f,
0.999994f, 0.999995f, 0.999995f, 0.999996f, 0.999996f,
0.999996f, 0.999997f, 0.999997f, 0.999997f, 0.999997f,
0.999997f, 0.999998f, 0.999998f, 0.999998f, 0.999998f,
0.999998f, 0.999998f, 0.999999f, 0.999999f, 0.999999f,
0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
0.999999f, 0.999999f, 0.999999f, 0.999999f, 0.999999f,
1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
1.000000f, 1.000000f, 1.000000f, 1.000000f, 1.000000f,
1.000000f,
};