shithub: opus

Download patch

ref: 222494f3ea66da5abb218508abf53dc40d13b99e
parent: 8a23fe977f1f273c84865a9bb5eef012fcdb7d3f
author: Jean-Marc Valin <[email protected]>
date: Wed Aug 17 11:53:37 EDT 2011

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.

--- a/libcelt/celt.c
+++ b/libcelt/celt.c
@@ -283,14 +283,6 @@
    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)
 {
 #ifdef FIXED_POINT
@@ -891,15 +883,9 @@
          > MULT16_32_Q15(m->eBands[13]<<(LM+1), sumLR);
 }
 
-#ifdef FIXED_POINT
 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;
    opus_int32 bits;
    ec_enc _enc;
@@ -1675,10 +1661,16 @@
       return nbCompressedBytes;
 }
 
+
+
 #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
-CELT_STATIC
-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_encode_float(CELTEncoder * restrict st, const float * pcm, int frame_size, unsigned char *compressed, int nbCompressedBytes)
 {
    int j, ret, C, N;
    VARDECL(opus_int16, in);
@@ -1694,7 +1686,7 @@
    for (j=0;j<C*N;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
    for (j=0;j<C*N;j++)
       ((float*)pcm)[j]=in[j]*(1.f/32768.f);
@@ -1701,12 +1693,11 @@
 #endif
    RESTORE_STACK;
    return ret;
-
 }
-#endif /*DISABLE_FLOAT_API*/
+#endif /* DISABLE_FLOAT_API */
 #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;
    VARDECL(celt_sig, in);
@@ -1722,7 +1713,7 @@
      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
    for (j=0;j<C*N;j++)
       ((opus_int16*)pcm)[j] = FLOAT2INT16(in[j]);
@@ -1730,20 +1721,14 @@
    RESTORE_STACK;
    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);
 }
 
-#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, ...)
 {
    va_list ap;
@@ -2252,15 +2237,9 @@
    RESTORE_STACK;
 }
 
-#ifdef FIXED_POINT
 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 spread_decision;
    opus_int32 bits;
@@ -2627,10 +2606,16 @@
    return frame_size/st->downsample;
 }
 
+
+
 #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
-CELT_STATIC
-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 celt_decode_float(CELTDecoder * restrict st, const unsigned char *data, int len, float * restrict pcm, int frame_size)
 {
    int j, ret, C, N;
    VARDECL(opus_int16, out);
@@ -2643,7 +2628,7 @@
    N = frame_size;
 
    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)
       for (j=0;j<C*ret;j++)
          pcm[j]=out[j]*(1.f/32768.f);
@@ -2651,11 +2636,17 @@
    RESTORE_STACK;
    return ret;
 }
-#endif /*DISABLE_FLOAT_API*/
+#endif /* DISABLE_FLOAT_API */
+
 #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;
    VARDECL(celt_sig, out);
    ALLOC_STACK;
@@ -2667,7 +2658,7 @@
    N = frame_size;
    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)
       for (j=0;j<C*ret;j++)
@@ -2676,19 +2667,9 @@
    RESTORE_STACK;
    return ret;
 }
+
 #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, ...)
 {
--- a/libcelt/float_cast.h
+++ b/libcelt/float_cast.h
@@ -123,4 +123,12 @@
 	#define	float2int(flt)		((int)(floor(.5+flt)))
 #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 */
--- a/libcelt/modes.h
+++ b/libcelt/modes.h
@@ -102,10 +102,8 @@
 #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) */
-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_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_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);
+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_decode_with_ec(CELTDecoder * restrict st, const unsigned char *data, int len, opus_val16 * restrict pcm, int frame_size, ec_dec *dec);
 #endif /* OPUS_BUILD */
 
 #endif
--- a/src/opus_decoder.c
+++ b/src/opus_decoder.c
@@ -38,7 +38,15 @@
 #include "entdec.h"
 #include "modes.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
    on really weird architectures) */
 static inline int align(int i)
@@ -109,7 +117,7 @@
     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 i, c;
@@ -142,7 +150,7 @@
 }
 
 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;
 	CELTDecoder *celt_dec;
@@ -150,8 +158,8 @@
 	ec_dec dec;
     silk_DecControlStruct DecControl;
     opus_int32 silk_frame_size;
-    opus_int16 pcm_celt[960*2];
-    opus_int16 pcm_transition[480*2];
+    VARDECL(opus_int16, pcm_silk);
+    VARDECL(opus_val16, pcm_transition);
 
     int audiosize;
     int mode;
@@ -160,10 +168,10 @@
     int redundancy=0;
     int redundancy_bytes = 0;
     int celt_to_silk=0;
-    opus_int16 redundant_audio[240*2];
     int c;
     int F2_5, F5, F10, F20;
     const opus_val16 *window;
+    ALLOC_STACK;
 
     silk_dec = (char*)st+st->silk_dec_offset;
     celt_dec = (CELTDecoder*)((char*)st+st->celt_dec_offset);
@@ -176,6 +184,7 @@
     {
     	data = NULL;
     	/* 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);
     }
     if (data != NULL)
@@ -190,6 +199,7 @@
     		/* If we haven't got any packet yet, all we can do is return zeros */
     		for (i=0;i<audiosize;i++)
     			pcm[i] = 0;
+    		RESTORE_STACK;
     		return audiosize;
     	} else {
     		mode = st->prev_mode;
@@ -196,6 +206,8 @@
     	}
     }
 
+    ALLOC(pcm_transition, F5*st->channels, opus_val16);
+
     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_HYBRID && st->prev_mode == MODE_SILK_ONLY))
@@ -202,21 +214,25 @@
     {
     	transition = 1;
     	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)
     {
         fprintf(stderr, "PCM buffer too small: %d vs %d (mode = %d)\n", audiosize, frame_size, mode);
+        RESTORE_STACK;
         return OPUS_BAD_ARG;
     } else {
         frame_size = audiosize;
     }
 
+    ALLOC(pcm_silk, frame_size*st->channels, opus_int16);
+    ALLOC(redundant_audio, F5*st->channels, opus_val16);
+
     /* SILK processing */
     if (mode != MODE_CELT_ONLY)
     {
         int lost_flag, decoded_samples;
-        opus_int16 *pcm_ptr = pcm;
+        opus_int16 *pcm_ptr = pcm_silk;
 
         if (st->prev_mode==MODE_CELT_ONLY)
         	silk_InitDecoder( silk_dec );
@@ -254,15 +270,14 @@
             		silk_frame_size = frame_size;
             		for (i=0;i<frame_size*st->channels;i++)
             			pcm_ptr[i] = 0;
-            	} else
-                    return OPUS_CORRUPTED_DATA;
+            	} else {
+            	   RESTORE_STACK;
+            	   return OPUS_CORRUPTED_DATA;
+            	}
             }
             pcm_ptr += silk_frame_size * st->channels;
             decoded_samples += silk_frame_size;
         } while( decoded_samples < frame_size );
-    } else {
-        for (i=0;i<frame_size*st->channels;i++)
-            pcm[i] = 0;
     }
 
     start_band = 0;
@@ -285,8 +300,10 @@
             	}
             }
             len -= redundancy_bytes;
-            if (len<0)
-                return OPUS_CORRUPTED_DATA;
+            if (len<0) {
+               RESTORE_STACK;
+               return OPUS_CORRUPTED_DATA;
+            }
             /* Shrink decoder because of raw bits */
             dec.storage -= redundancy_bytes;
         }
@@ -321,13 +338,13 @@
         transition = 0;
 
     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*/
     if (redundancy && celt_to_silk)
     {
         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);
     }
 
@@ -341,12 +358,24 @@
     {
     	int celt_frame_size = IMIN(F20, frame_size);
         /* Decode CELT */
-        celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm_celt, celt_frame_size, &dec);
-        for (i=0;i<celt_frame_size*st->channels;i++)
-            pcm[i] = SAT16(pcm[i] + (int)pcm_celt[i]);
+        celt_ret = celt_decode_with_ec(celt_dec, decode_fec?NULL:data, len, pcm, celt_frame_size, &dec);
+    } else {
+       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
+    }
+
+    {
         const CELTMode *celt_mode;
         celt_decoder_ctl(celt_dec, CELT_GET_MODE(&celt_mode));
         window = celt_mode->window;
@@ -358,7 +387,7 @@
         celt_decoder_ctl(celt_dec, CELT_RESET_STATE);
         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,
         		pcm+st->channels*(frame_size-F2_5), F2_5, st->channels, window, st->Fs);
     }
@@ -386,6 +415,7 @@
 
     st->prev_mode = mode;
     st->prev_redundancy = redundancy;
+    RESTORE_STACK;
 	return celt_ret<0 ? celt_ret : audiosize;
 
 }
@@ -528,9 +558,13 @@
    return count;
 }
 
-
+#ifdef FIXED_POINT
 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 count;
@@ -566,6 +600,49 @@
 	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, ...)
 {
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -38,7 +38,15 @@
 #include "entenc.h"
 #include "modes.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
    middle (memoriless) threshold. The second column is the hysteresis
    (difference with the middle) */
@@ -161,9 +169,13 @@
     	return NULL;
     return opus_encoder_init((OpusEncoder*)raw_state, Fs, channels, mode);
 }
-
-int opus_encode(OpusEncoder *st, const opus_int16 *pcm, int frame_size,
+#ifdef FIXED_POINT
+int opus_encode(OpusEncoder *st, const opus_val16 *pcm, int frame_size,
 		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;
     CELTEncoder *celt_enc;
@@ -179,12 +191,11 @@
     int redundancy = 0;
     int redundancy_bytes = 0;
     int celt_to_silk = 0;
-    /* TODO: This is 60 only so we can handle 60ms speech/audio switching
-       it shouldn't be too hard to reduce to 20 ms if needed */
-    opus_int16 pcm_buf[60*48*2];
+    VARDECL(opus_val16, pcm_buf);
     int nb_compr_bytes;
     int to_celt = 0;
     opus_int32 mono_rate;
+    ALLOC_STACK;
 
     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)
@@ -378,6 +389,12 @@
     /* SILK processing */
     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;
         if( st->mode == MODE_HYBRID ) {
             st->silk_mode.bitRate /= st->stream_channels;
@@ -429,10 +446,22 @@
         if (prefill)
         {
             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 ) {
             fprintf (stderr, "SILK encode error: %d\n", ret);
             /* Handle error */
@@ -487,7 +516,7 @@
             celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(0));
             celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
             /* 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 {
             celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(2));
         }
@@ -519,6 +548,7 @@
         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++)
         pcm_buf[i] = st->delay_buffer[(st->encoder_buffer-st->delay_compensation)*st->channels+i];
     for (;i<frame_size*st->channels;i++)
@@ -588,7 +618,7 @@
     {
         celt_encoder_ctl(celt_enc, CELT_SET_START_BAND(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);
     }
 
@@ -611,9 +641,9 @@
         celt_encoder_ctl(celt_enc, CELT_SET_PREDICTION(0));
 
         /* 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);
     }
 
 
@@ -668,6 +698,45 @@
     st->first = 0;
     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, ...)
 {
--- a/src/opus_encoder.h
+++ b/src/opus_encoder.h
@@ -31,8 +31,8 @@
 #include "celt.h"
 #include "opus.h"
 #include "silk_API.h"
+#include "arch.h"
 
-/* FIXME: This is only valid for 48 kHz */
 #define MAX_ENCODER_BUFFER 480
 
 struct OpusEncoder {
@@ -60,7 +60,7 @@
     int          encoder_buffer;
     int          delay_compensation;
     int          first;
-    short        delay_buffer[MAX_ENCODER_BUFFER*2];
+    opus_val16   delay_buffer[MAX_ENCODER_BUFFER*2];
 
     int          rangeFinal;
 };
--- a/src/test_opus.c
+++ b/src/test_opus.c
@@ -380,6 +380,8 @@
                 {
                     fwrite(out+skip, sizeof(short)*channels, output_samples-skip, fout);
                     skip = 0;
+                } else {
+                   fprintf(stderr, "error decoding frame: %s\n", opus_strerror(output_samples));
                 }
             }
         }