Adds a floating-point API to Opus

The high-level Opus encoder and decoder can now be compiled as
either fixed or float. Also, we now use the stack_alloc.h macros
in the top-level Opus code.
This commit is contained in:
Jean-Marc Valin 2011-08-17 15:53:37 -04:00
parent 8a23fe977f
commit 222494f3ea
7 changed files with 230 additions and 95 deletions

View file

@ -283,14 +283,6 @@ void celt_encoder_destroy(CELTEncoder *st)
celt_free(st); celt_free(st);
} }
static inline opus_int16 FLOAT2INT16(float x)
{
x = x*CELT_SIG_SCALE;
x = MAX32(x, -32768);
x = MIN32(x, 32767);
return (opus_int16)float2int(x);
}
static inline opus_val16 SIG2WORD16(celt_sig x) static inline opus_val16 SIG2WORD16(celt_sig x)
{ {
#ifdef FIXED_POINT #ifdef FIXED_POINT
@ -891,15 +883,9 @@ static int stereo_analysis(const CELTMode *m, const celt_norm *X,
> MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR); > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
} }
#ifdef FIXED_POINT
CELT_STATIC CELT_STATIC
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
{ {
#else
CELT_STATIC
int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
{
#endif
int i, c, N; int i, c, N;
opus_int32 bits; opus_int32 bits;
ec_enc _enc; ec_enc _enc;
@ -1675,10 +1661,16 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const celt_sig * pcm, i
return nbCompressedBytes; return nbCompressedBytes;
} }
#ifdef FIXED_POINT #ifdef FIXED_POINT
int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{
return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
}
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
CELT_STATIC int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc)
{ {
int j, ret, C, N; int j, ret, C, N;
VARDECL(opus_int16, in); VARDECL(opus_int16, in);
@ -1694,19 +1686,18 @@ int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int
for (j=0;j<C*N;j++) for (j=0;j<C*N;j++)
in[j] = FLOAT2INT16(pcm[j]); in[j] = FLOAT2INT16(pcm[j]);
ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, enc); ret=celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
#ifdef RESYNTH #ifdef RESYNTH
for (j=0;j<C*N;j++) for (j=0;j<C*N;j++)
((float*)pcm)[j]=in[j]*(1.f/32768.f); ((float*)pcm)[j]=in[j]*(1.f/32768.f);
#endif #endif
RESTORE_STACK; RESTORE_STACK;
return ret; return ret;
} }
#endif /* DISABLE_FLOAT_API */ #endif /* DISABLE_FLOAT_API */
#else #else
CELT_STATIC
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc) int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{ {
int j, ret, C, N; int j, ret, C, N;
VARDECL(celt_sig, in); VARDECL(celt_sig, in);
@ -1722,7 +1713,7 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int f
in[j] = SCALEOUT(pcm[j]); in[j] = SCALEOUT(pcm[j]);
} }
ret = celt_encode_with_ec_float(st,in,frame_size,compressed,nbCompressedBytes, enc); ret = celt_encode_with_ec(st,in,frame_size,compressed,nbCompressedBytes, NULL);
#ifdef RESYNTH #ifdef RESYNTH
for (j=0;j<C*N;j++) for (j=0;j<C*N;j++)
((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]); ((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
@ -1730,20 +1721,14 @@ int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int f
RESTORE_STACK; RESTORE_STACK;
return ret; return ret;
} }
#endif
int celt_encode(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes) int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{ {
return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL); return celt_encode_with_ec(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
} }
#ifndef DISABLE_FLOAT_API
int celt_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
{
return celt_encode_with_ec_float(st, pcm, frame_size, compressed, nbCompressedBytes, NULL);
}
#endif /* DISABLE_FLOAT_API */
#endif
int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...) int celt_encoder_ctl(CELTEncoder * restrict st, int request, ...)
{ {
va_list ap; va_list ap;
@ -2252,15 +2237,9 @@ static void celt_decode_lost(CELTDecoder * restrict st, opus_val16 * restrict pc
RESTORE_STACK; RESTORE_STACK;
} }
#ifdef FIXED_POINT
CELT_STATIC CELT_STATIC
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec) int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec)
{ {
#else
CELT_STATIC
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, celt_sig * restrict pcm, int frame_size, ec_dec *dec)
{
#endif
int c, i, N; int c, i, N;
int spread_decision; int spread_decision;
opus_int32 bits; opus_int32 bits;
@ -2627,10 +2606,16 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
return frame_size/st->downsample; return frame_size/st->downsample;
} }
#ifdef FIXED_POINT #ifdef FIXED_POINT
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
{
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
}
#ifndef DISABLE_FLOAT_API #ifndef DISABLE_FLOAT_API
CELT_STATIC int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec)
{ {
int j, ret, C, N; int j, ret, C, N;
VARDECL(opus_int16, out); VARDECL(opus_int16, out);
@ -2643,7 +2628,7 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
N = frame_size; N = frame_size;
ALLOC(out, C*N, opus_int16); ALLOC(out, C*N, opus_int16);
ret=celt_decode_with_ec(st, data, len, out, frame_size, dec); ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
if (ret>0) if (ret>0)
for (j=0;j<C*ret;j++) for (j=0;j<C*ret;j++)
pcm[j]=out[j]*(1.f/32768.f); pcm[j]=out[j]*(1.f/32768.f);
@ -2652,9 +2637,15 @@ int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *da
return ret; return ret;
} }
#endif /* DISABLE_FLOAT_API */ #endif /* DISABLE_FLOAT_API */
#else #else
CELT_STATIC
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec) int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
{
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
}
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
{ {
int j, ret, C, N; int j, ret, C, N;
VARDECL(celt_sig, out); VARDECL(celt_sig, out);
@ -2667,7 +2658,7 @@ int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, in
N = frame_size; N = frame_size;
ALLOC(out, C*N, celt_sig); ALLOC(out, C*N, celt_sig);
ret=celt_decode_with_ec_float(st, data, len, out, frame_size, dec); ret=celt_decode_with_ec(st, data, len, out, frame_size, NULL);
if (ret>0) if (ret>0)
for (j=0;j<C*ret;j++) for (j=0;j<C*ret;j++)
@ -2676,19 +2667,9 @@ int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, in
RESTORE_STACK; RESTORE_STACK;
return ret; return ret;
} }
#endif #endif
int celt_decode(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size)
{
return celt_decode_with_ec(st, data, len, pcm, frame_size, NULL);
}
#ifndef DISABLE_FLOAT_API
int celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
{
return celt_decode_with_ec_float(st, data, len, pcm, frame_size, NULL);
}
#endif /* DISABLE_FLOAT_API */
int celt_decoder_ctl(CELTDecoder * restrict st, int request, ...) int celt_decoder_ctl(CELTDecoder * restrict st, int request, ...)
{ {

View file

@ -123,4 +123,12 @@
#define float2int(flt) ((int)(floor(.5+flt))) #define float2int(flt) ((int)(floor(.5+flt)))
#endif #endif
static inline opus_int16 FLOAT2INT16(float x)
{
x = x*CELT_SIG_SCALE;
x = MAX32(x, -32768);
x = MIN32(x, 32767);
return (opus_int16)float2int(x);
}
#endif /* FLOAT_CAST_H */ #endif /* FLOAT_CAST_H */

View file

@ -102,10 +102,8 @@ struct CELTMode {
#define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x) #define CELT_GET_MODE(x) CELT_GET_MODE_REQUEST, _celt_check_mode_ptr_ptr(x)
/* Prototypes for _ec versions of the encoder/decoder calls (not public) */ /* Prototypes for _ec versions of the encoder/decoder calls (not public) */
int celt_encode_with_ec(CELTEncoder * restrict st, const opus_int16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); int celt_encode_with_ec(CELTEncoder * restrict st, const opus_val16 * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc);
int celt_encode_with_ec_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes, ec_enc *enc); int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec);
int celt_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_int16 * restrict pcm, int frame_size, ec_dec *dec);
int celt_decode_with_ec_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size, ec_dec *dec);
#endif /* OPUS_BUILD */ #endif /* OPUS_BUILD */
#endif #endif

View file

@ -38,6 +38,14 @@
#include "entdec.h" #include "entdec.h"
#include "modes.h" #include "modes.h"
#include "silk_API.h" #include "silk_API.h"
#include "stack_alloc.h"
#include "float_cast.h"
#ifdef FIXED_POINT
#define celt_decode_native celt_decode
#else
#define celt_decode_native celt_decode_float
#endif
/* Make sure everything's aligned to 4 bytes (this may need to be increased /* Make sure everything's aligned to 4 bytes (this may need to be increased
on really weird architectures) */ on really weird architectures) */
@ -109,7 +117,7 @@ OpusDecoder *opus_decoder_create(int Fs, int channels)
return opus_decoder_init((OpusDecoder*)raw_state, Fs, channels); return opus_decoder_init((OpusDecoder*)raw_state, Fs, channels);
} }
static void smooth_fade(const opus_int16 *in1, const opus_int16 *in2, opus_int16 *out, static void smooth_fade(const opus_val16 *in1, const opus_val16 *in2, opus_val16 *out,
int overlap, int channels, const opus_val16 *window, int Fs) int overlap, int channels, const opus_val16 *window, int Fs)
{ {
int i, c; int i, c;
@ -142,7 +150,7 @@ static int opus_packet_get_mode(const unsigned char *data)
} }
static int opus_decode_frame(OpusDecoder *st, const unsigned char *data, static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
int len, opus_int16 *pcm, int frame_size, int decode_fec) int len, opus_val16 *pcm, int frame_size, int decode_fec)
{ {
void *silk_dec; void *silk_dec;
CELTDecoder *celt_dec; CELTDecoder *celt_dec;
@ -150,8 +158,8 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
ec_dec dec; ec_dec dec;
silk_DecControlStruct DecControl; silk_DecControlStruct DecControl;
opus_int32 silk_frame_size; opus_int32 silk_frame_size;
opus_int16 pcm_celt[960*2]; VARDECL(opus_int16, pcm_silk);
opus_int16 pcm_transition[480*2]; VARDECL(opus_val16, pcm_transition);
int audiosize; int audiosize;
int mode; int mode;
@ -160,10 +168,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
int redundancy=0; int redundancy=0;
int redundancy_bytes = 0; int redundancy_bytes = 0;
int celt_to_silk=0; int celt_to_silk=0;
opus_int16 redundant_audio[240*2];
int c; int c;
int F2_5, F5, F10, F20; int F2_5, F5, F10, F20;
const opus_val16 *window; const opus_val16 *window;
ALLOC_STACK;
silk_dec = (char*)st+st->silk_dec_offset; silk_dec = (char*)st+st->silk_dec_offset;
celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset); celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
@ -176,6 +184,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
{ {
data = NULL; data = NULL;
/* In that case, don't conceal more than what the ToC says */ /* In that case, don't conceal more than what the ToC says */
/* FIXME: What if st->frame_size has never been set? */
frame_size = IMIN(frame_size, st->frame_size); frame_size = IMIN(frame_size, st->frame_size);
} }
if (data != NULL) if (data != NULL)
@ -190,33 +199,40 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
/* If we haven't got any packet yet, all we can do is return zeros */ /* If we haven't got any packet yet, all we can do is return zeros */
for (i=0;i<audiosize;i++) for (i=0;i<audiosize;i++)
pcm[i] = 0; pcm[i] = 0;
RESTORE_STACK;
return audiosize; return audiosize;
} else { } else {
mode = st->prev_mode; mode = st->prev_mode;
} }
} }
ALLOC(pcm_transition, F5*st->channels, opus_val16);
if (data!=NULL && !st->prev_redundancy && mode != st->prev_mode && st->prev_mode > 0 if (data!=NULL && !st->prev_redundancy && mode != st->prev_mode && st->prev_mode > 0
&& !(mode == MODE_SILK_ONLY && st->prev_mode == MODE_HYBRID) && !(mode == MODE_SILK_ONLY && st->prev_mode == MODE_HYBRID)
&& !(mode == MODE_HYBRID && st->prev_mode == MODE_SILK_ONLY)) && !(mode == MODE_HYBRID && st->prev_mode == MODE_SILK_ONLY))
{ {
transition = 1; transition = 1;
if (mode == MODE_CELT_ONLY) if (mode == MODE_CELT_ONLY)
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0); opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
} }
if (audiosize > frame_size) if (audiosize > frame_size)
{ {
fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode); fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);
RESTORE_STACK;
return OPUS_BAD_ARG; return OPUS_BAD_ARG;
} else { } else {
frame_size = audiosize; frame_size = audiosize;
} }
ALLOC(pcm_silk, frame_size*st->channels, opus_int16);
ALLOC(redundant_audio, F5*st->channels, opus_val16);
/* SILK processing */ /* SILK processing */
if (mode != MODE_CELT_ONLY) if (mode != MODE_CELT_ONLY)
{ {
int lost_flag, decoded_samples; int lost_flag, decoded_samples;
opus_int16 *pcm_ptr = pcm; opus_int16 *pcm_ptr = pcm_silk;
if (st->prev_mode==MODE_CELT_ONLY) if (st->prev_mode==MODE_CELT_ONLY)
silk_InitDecoder( silk_dec ); silk_InitDecoder( silk_dec );
@ -254,15 +270,14 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
silk_frame_size = frame_size; silk_frame_size = frame_size;
for (i=0;i<frame_size*st->channels;i++) for (i=0;i<frame_size*st->channels;i++)
pcm_ptr[i] = 0; pcm_ptr[i] = 0;
} else } else {
RESTORE_STACK;
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
} }
}
pcm_ptr += silk_frame_size * st->channels; pcm_ptr += silk_frame_size * st->channels;
decoded_samples += silk_frame_size; decoded_samples += silk_frame_size;
} while( decoded_samples < frame_size ); } while( decoded_samples < frame_size );
} else {
for (i=0;i<frame_size*st->channels;i++)
pcm[i] = 0;
} }
start_band = 0; start_band = 0;
@ -285,8 +300,10 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
} }
} }
len -= redundancy_bytes; len -= redundancy_bytes;
if (len<0) if (len<0) {
RESTORE_STACK;
return OPUS_CORRUPTED_DATA; return OPUS_CORRUPTED_DATA;
}
/* Shrink decoder because of raw bits */ /* Shrink decoder because of raw bits */
dec.storage -= redundancy_bytes; dec.storage -= redundancy_bytes;
} }
@ -321,13 +338,13 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
transition = 0; transition = 0;
if (transition && mode != MODE_CELT_ONLY) if (transition && mode != MODE_CELT_ONLY)
opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F10, audiosize), 0); opus_decode_frame(st, NULL, 0, pcm_transition, IMIN(F5, audiosize), 0);
/* 5 ms redundant frame for CELT->SILK*/ /* 5 ms redundant frame for CELT->SILK*/
if (redundancy && celt_to_silk) if (redundancy && celt_to_silk)
{ {
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5); celt_decode_native(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
celt_decoder_ctl(celt_dec, CELT_RESET_STATE); celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
} }
@ -341,9 +358,21 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
{ {
int celt_frame_size = IMIN(F20, frame_size); int celt_frame_size = IMIN(F20, frame_size);
/* Decode CELT */ /* Decode CELT */
celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm_celt, celt_frame_size, &dec); celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm, celt_frame_size, &dec);
for (i=0;i<celt_frame_size*st->channels;i++) } else {
pcm[i] = SAT16(pcm[i] + (int)pcm_celt[i]); for (i=0;i<frame_size*st->channels;i++)
pcm[i] = 0;
}
if (mode != MODE_CELT_ONLY)
{
#ifdef FIXED_POINT
for (i=0;i<frame_size*st->channels;i++)
pcm[i] = SAT16(pcm[i] + pcm_silk[i]);
#else
for (i=0;i<frame_size*st->channels;i++)
pcm[i] = pcm[i] + (1./32768.)*pcm_silk[i];
#endif
} }
{ {
@ -358,7 +387,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
celt_decoder_ctl(celt_dec, CELT_RESET_STATE); celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0)); celt_decoder_ctl(celt_dec, CELT_SET_START_BAND(0));
celt_decode(celt_dec, data+len, redundancy_bytes, redundant_audio, F5); celt_decode_native(celt_dec, data+len, redundancy_bytes, redundant_audio, F5);
smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5, smooth_fade(pcm+st->channels*(frame_size-F2_5), redundant_audio+st->channels*F2_5,
pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs); pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
} }
@ -386,6 +415,7 @@ static int opus_decode_frame(OpusDecoder *st, const unsigned char *data,
st->prev_mode = mode; st->prev_mode = mode;
st->prev_redundancy = redundancy; st->prev_redundancy = redundancy;
RESTORE_STACK;
return celt_ret<0 ? celt_ret : audiosize; return celt_ret<0 ? celt_ret : audiosize;
} }
@ -528,9 +558,13 @@ int opus_packet_parse(const unsigned char *data, int len,
return count; return count;
} }
#ifdef FIXED_POINT
int opus_decode(OpusDecoder *st, const unsigned char *data, int opus_decode(OpusDecoder *st, const unsigned char *data,
int len, opus_int16 *pcm, int frame_size, int decode_fec) int len, opus_val16 *pcm, int frame_size, int decode_fec)
#else
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
int len, opus_val16 *pcm, int frame_size, int decode_fec)
#endif
{ {
int i, nb_samples; int i, nb_samples;
int count; int count;
@ -566,6 +600,49 @@ int opus_decode(OpusDecoder *st, const unsigned char *data,
return nb_samples; return nb_samples;
} }
#ifdef FIXED_POINT
#ifndef DISABLE_FLOAT_API
int opus_decode_float(OpusDecoder *st, const unsigned char *data,
int len, float *pcm, int frame_size, int decode_fec)
{
VARDECL(opus_int16, out);
int ret, i;
ALLOC_STACK;
ALLOC(out, frame_size*st->channels, opus_int16);
ret = opus_decode(st, data, len, out, frame_size, decode_fec);
if (ret > 0)
{
for (i=0;i<ret*st->channels;i++)
pcm[i] = (1./32768.)*(out[i]);
}
RESTORE_STACK;
return ret;
}
#endif
#else
int opus_decode(OpusDecoder *st, const unsigned char *data,
int len, opus_int16 *pcm, int frame_size, int decode_fec)
{
VARDECL(float, out);
int ret, i;
ALLOC_STACK;
ALLOC(out, frame_size*st->channels, float);
ret = opus_decode_float(st, data, len, out, frame_size, decode_fec);
if (ret > 0)
{
for (i=0;i<ret*st->channels;i++)
pcm[i] = FLOAT2INT16(out[i]);
}
RESTORE_STACK;
return ret;
}
#endif
int opus_decoder_ctl(OpusDecoder *st, int request, ...) int opus_decoder_ctl(OpusDecoder *st, int request, ...)
{ {

View file

@ -38,6 +38,14 @@
#include "entenc.h" #include "entenc.h"
#include "modes.h" #include "modes.h"
#include "silk_API.h" #include "silk_API.h"
#include "stack_alloc.h"
#include "float_cast.h"
#ifdef FIXED_POINT
#define celt_encode_native celt_encode
#else
#define celt_encode_native celt_encode_float
#endif
/* Transition tables for the voice and audio modes. First column is the /* Transition tables for the voice and audio modes. First column is the
middle (memoriless) threshold. The second column is the hysteresis middle (memoriless) threshold. The second column is the hysteresis
@ -161,9 +169,13 @@ OpusEncoder *opus_encoder_create(int Fs, int channels, int mode)
return NULL; return NULL;
return opus_encoder_init((OpusEncoder*)raw_state, Fs, channels, mode); return opus_encoder_init((OpusEncoder*)raw_state, Fs, channels, mode);
} }
#ifdef FIXED_POINT
int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size, int opus_encode(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
unsigned char *data, int max_data_bytes) unsigned char *data, int max_data_bytes)
#else
int opus_encode_float(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
unsigned char *data, int max_data_bytes)
#endif
{ {
void *silk_enc; void *silk_enc;
CELTEncoder *celt_enc; CELTEncoder *celt_enc;
@ -179,12 +191,11 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
int redundancy = 0; int redundancy = 0;
int redundancy_bytes = 0; int redundancy_bytes = 0;
int celt_to_silk = 0; int celt_to_silk = 0;
/* TODO: This is 60 only so we can handle 60ms speech/audio switching VARDECL(opus_val16, pcm_buf);
it shouldn't be too hard to reduce to 20 ms if needed */
opus_int16 pcm_buf[60*48*2];
int nb_compr_bytes; int nb_compr_bytes;
int to_celt = 0; int to_celt = 0;
opus_int32 mono_rate; opus_int32 mono_rate;
ALLOC_STACK;
if (400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs && if (400*frame_size != st->Fs && 200*frame_size != st->Fs && 100*frame_size != st->Fs &&
50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs) 50*frame_size != st->Fs && 25*frame_size != st->Fs && 50*frame_size != 3*st->Fs)
@ -378,6 +389,12 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
/* SILK processing */ /* SILK processing */
if (st->mode != MODE_CELT_ONLY) if (st->mode != MODE_CELT_ONLY)
{ {
#ifdef FIXED_POINT
const opus_int16 *pcm_silk;
#else
VARDECL(opus_int16, pcm_silk);
ALLOC(pcm_silk, st->channels*frame_size, opus_int16);
#endif
st->silk_mode.bitRate = st->bitrate_bps - 8*st->Fs/frame_size; st->silk_mode.bitRate = st->bitrate_bps - 8*st->Fs/frame_size;
if( st->mode == MODE_HYBRID ) { if( st->mode == MODE_HYBRID ) {
st->silk_mode.bitRate /= st->stream_channels; st->silk_mode.bitRate /= st->stream_channels;
@ -429,10 +446,22 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
if (prefill) if (prefill)
{ {
int zero=0; int zero=0;
silk_Encode( silk_enc, &st->silk_mode, st->delay_buffer, st->encoder_buffer, NULL, &zero, 1 ); #ifdef FIXED_POINT
pcm_silk = st->delay_buffer;
#else
for (i=0;i<st->encoder_buffer*st->channels;i++)
pcm_silk[i] = FLOAT2INT16(st->delay_buffer[i]);
#endif
silk_Encode( silk_enc, &st->silk_mode, pcm_silk, st->encoder_buffer, NULL, &zero, 1 );
} }
ret = silk_Encode( silk_enc, &st->silk_mode, pcm, frame_size, &enc, &nBytes, 0 ); #ifdef FIXED_POINT
pcm_silk = pcm;
#else
for (i=0;i<frame_size*st->channels;i++)
pcm_silk[i] = FLOAT2INT16(pcm[i]);
#endif
ret = silk_Encode( silk_enc, &st->silk_mode, pcm_silk, frame_size, &enc, &nBytes, 0 );
if( ret ) { if( ret ) {
fprintf (stderr, "SILK encode error: %d\n", ret); fprintf (stderr, "SILK encode error: %d\n", ret);
/* Handle error */ /* Handle error */
@ -487,7 +516,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
/* TODO: This wastes CPU a bit compared to just prefilling the buffer */ /* TODO: This wastes CPU a bit compared to just prefilling the buffer */
celt_encode(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10); celt_encode_native(celt_enc, &st->delay_buffer[(st->encoder_buffer-st->delay_compensation-st->Fs/400)*st->channels], st->Fs/400, dummy, 10);
} else { } else {
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2)); celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2));
} }
@ -519,6 +548,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
nb_compr_bytes = 0; nb_compr_bytes = 0;
} }
ALLOC(pcm_buf, IMAX(frame_size, st->Fs/200)*st->channels, opus_val16);
for (i=0;i<IMIN(frame_size, st->delay_compensation)*st->channels;i++) for (i=0;i<IMIN(frame_size, st->delay_compensation)*st->channels;i++)
pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i]; pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i];
for (;i<frame_size*st->channels;i++) for (;i<frame_size*st->channels;i++)
@ -588,7 +618,7 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
{ {
celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0)); celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
celt_encoder_ctl(celt_enc, CELT_SET_VBR(0)); celt_encoder_ctl(celt_enc, CELT_SET_VBR(0));
celt_encode(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes); celt_encode_native(celt_enc, pcm_buf, st->Fs/200, data+nb_compr_bytes, redundancy_bytes);
celt_encoder_ctl(celt_enc, CELT_RESET_STATE); celt_encoder_ctl(celt_enc, CELT_RESET_STATE);
} }
@ -611,9 +641,9 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0)); celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
/* TODO: We could speed up prefilling here */ /* TODO: We could speed up prefilling here */
celt_encode(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, data+nb_compr_bytes, redundancy_bytes); celt_encode_native(celt_enc, pcm_buf+st->channels*(frame_size-N2-N4), N4, data+nb_compr_bytes, redundancy_bytes);
celt_encode(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes); celt_encode_native(celt_enc, pcm_buf+st->channels*(frame_size-N2), N2, data+nb_compr_bytes, redundancy_bytes);
} }
@ -669,6 +699,45 @@ int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
return ret+1+redundancy_bytes; return ret+1+redundancy_bytes;
} }
#ifdef FIXED_POINT
#ifndef DISABLE_FLOAT_API
int opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size,
unsigned char *data, int max_data_bytes)
{
int i, ret;
VARDECL(opus_int16, in);
ALLOC_STACK;
ALLOC(in, frame_size*st->channels, opus_int16);
for (i=0;i<frame_size*st->channels;i++)
in[i] = FLOAT2INT16(pcm[i]);
ret = opus_encode(st, in, frame_size, data, max_data_bytes);
RESTORE_STACK;
return ret;
}
#endif
#else
int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
unsigned char *data, int max_data_bytes)
{
int i, ret;
VARDECL(float, in);
ALLOC_STACK;
ALLOC(in, frame_size*st->channels, float);
for (i=0;i<frame_size*st->channels;i++)
in[i] = (1./32768)*pcm[i];
ret = opus_encode_float(st, in, frame_size, data, max_data_bytes);
RESTORE_STACK;
return ret;
}
#endif
int opus_encoder_ctl(OpusEncoder *st, int request, ...) int opus_encoder_ctl(OpusEncoder *st, int request, ...)
{ {
CELTEncoder *celt_enc; CELTEncoder *celt_enc;

View file

@ -31,8 +31,8 @@
#include "celt.h" #include "celt.h"
#include "opus.h" #include "opus.h"
#include "silk_API.h" #include "silk_API.h"
#include "arch.h"
/* FIXME: This is only valid for 48 kHz */
#define MAX_ENCODER_BUFFER 480 #define MAX_ENCODER_BUFFER 480
struct OpusEncoder { struct OpusEncoder {
@ -60,7 +60,7 @@ struct OpusEncoder {
int encoder_buffer; int encoder_buffer;
int delay_compensation; int delay_compensation;
int first; int first;
short delay_buffer[MAX_ENCODER_BUFFER*2]; opus_val16 delay_buffer[MAX_ENCODER_BUFFER*2];
int rangeFinal; int rangeFinal;
}; };

View file

@ -380,6 +380,8 @@ int main(int argc, char *argv[])
{ {
fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout); fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout);
skip = 0; skip = 0;
} else {
fprintf(stderr, "error decoding frame: %s\n", opus_strerror(output_samples));
} }
} }
} }