shithub: opus

Download patch

ref: 91904a4c91eb19abcebe843045f4599ee67adbee
parent: 0f68696a97ca2e42ec452fef1dc421faa3aa2092
author: Jean-Marc Valin <[email protected]>
date: Thu Sep 5 17:34:43 EDT 2013

Moves the analysis back to opus_encode_native() to it runs for all streams.

I checked that it's not *completely* busted, but it probably needs more testing.

--- a/src/analysis.c
+++ b/src/analysis.c
@@ -184,12 +184,12 @@
    for (;i<DETECT_SIZE;i++)
       psum += tonal->pspeech[i];
    psum = psum*tonal->music_confidence + (1-psum)*tonal->speech_confidence;
-   /*printf("%f %f\n", psum, info_out->music_prob);*/
+   /*printf("%f %f %f\n", psum, info_out->music_prob, info_out->tonality);*/
 
    info_out->music_prob = psum;
 }
 
-void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, const CELTMode *celt_mode, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix)
+void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info_out, 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;
@@ -234,7 +234,7 @@
     kfft = celt_mode->mdct.kfft[0];
     if (tonal->count==0)
        tonal->mem_fill = 240;
-    downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, C);
+    downmix(x, &tonal->inmem[tonal->mem_fill], IMIN(len, ANALYSIS_BUF_SIZE-tonal->mem_fill), offset, c1, c2, C);
     if (tonal->mem_fill+len < ANALYSIS_BUF_SIZE)
     {
        tonal->mem_fill += len;
@@ -260,7 +260,7 @@
     }
     OPUS_MOVE(tonal->inmem, tonal->inmem+ANALYSIS_BUF_SIZE-240, 240);
     remaining = len - (ANALYSIS_BUF_SIZE-tonal->mem_fill);
-    downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, C);
+    downmix(x, &tonal->inmem[240], remaining, offset+ANALYSIS_BUF_SIZE-tonal->mem_fill, c1, c2, C);
     tonal->mem_fill = 240 + remaining;
     opus_fft(kfft, in, out);
 
@@ -611,8 +611,8 @@
     RESTORE_STACK;
 }
 
-int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *pcm,
-                        const void *analysis_pcm, int frame_size, int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const opus_val16 *pcm,
+                        const void *analysis_pcm, int frame_size, int variable_duration, int c1, int c2, int C, opus_int32 Fs, int bitrate_bps,
                         int delay_compensation, int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info)
 {
    int offset;
@@ -622,9 +622,9 @@
    frame_size = IMIN((DETECT_SIZE-5)*Fs/100, frame_size);
 
    pcm_len = frame_size - analysis->analysis_offset;
-   offset = 0;
+   offset = analysis->analysis_offset;
    do {
-      tonality_analysis(analysis, NULL, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, C, lsb_depth, downmix);
+      tonality_analysis(analysis, NULL, celt_mode, analysis_pcm, IMIN(480, pcm_len), offset, c1, c2, C, lsb_depth, downmix);
       offset += 480;
       pcm_len -= 480;
    } while (pcm_len>0);
@@ -633,7 +633,7 @@
    if (variable_duration == OPUS_FRAMESIZE_VARIABLE && frame_size >= Fs/200)
    {
       int LM = 3;
-      LM = optimize_framesize((const opus_val16*)pcm, frame_size, C, Fs, bitrate_bps,
+      LM = optimize_framesize(pcm, frame_size, C, Fs, bitrate_bps,
             analysis->prev_tonality, analysis->subframe_mem, delay_compensation, downmix);
       while ((Fs/400<<LM)>frame_size)
          LM--;
--- a/src/analysis.h
+++ b/src/analysis.h
@@ -79,12 +79,12 @@
 } TonalityAnalysisState;
 
 void tonality_analysis(TonalityAnalysisState *tonal, AnalysisInfo *info,
-     const CELTMode *celt_mode, const void *x, int len, int offset, int C, int lsb_depth, downmix_func downmix);
+     const CELTMode *celt_mode, const void *x, int len, int offset, int c1, int c2, int C, int lsb_depth, downmix_func downmix);
 
 void tonality_get_info(TonalityAnalysisState *tonal, AnalysisInfo *info_out, int len);
 
-int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const void *pcm,
-                        const void *analysis_pcm, int frame_size, int variable_duration, int C, opus_int32 Fs, int bitrate_bps,
+int run_analysis(TonalityAnalysisState *analysis, const CELTMode *celt_mode, const opus_val16 *pcm,
+                        const void *analysis_pcm, int frame_size, int variable_duration, int c1, int c2, int C, opus_int32 Fs, int bitrate_bps,
                         int delay_compensation, int lsb_depth, downmix_func downmix, AnalysisInfo *analysis_info);
 
 #endif
--- a/src/opus_encoder.c
+++ b/src/opus_encoder.c
@@ -685,32 +685,6 @@
    return best_state;
 }
 
-void downmix_float(const void *_x, float *sub, int subframe, int offset, int C)
-{
-   const float *x;
-   int c, j;
-   x = (const float *)_x;
-   for (j=0;j<subframe;j++)
-      sub[j] = x[(j+offset)*C];
-   for (c=1;c<C;c++)
-      for (j=0;j<subframe;j++)
-         sub[j] += x[(j+offset)*C+c];
-}
-
-void downmix_int(const void *_x, float *sub, int subframe, int offset, int C)
-{
-   const opus_int16 *x;
-   int c, j;
-   x = (const opus_int16 *)_x;
-   for (j=0;j<subframe;j++)
-      sub[j] = x[(j+offset)*C];
-   for (c=1;c<C;c++)
-      for (j=0;j<subframe;j++)
-         sub[j] += x[(j+offset)*C+c];
-   for (j=0;j<subframe;j++)
-      sub[j] *= (1.f/32768);
-}
-
 int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
                 int bitrate, opus_val16 tonality, opus_val32 *mem, int buffering,
                 downmix_func downmix)
@@ -754,7 +728,7 @@
       int j;
       tmp=EPSILON;
 
-      downmix(x, sub, subframe, i*subframe, C);
+      downmix(x, sub, subframe, i*subframe, 0, -2, C);
       if (i==0)
          memx = sub[0];
       for (j=0;j<subframe;j++)
@@ -784,6 +758,54 @@
 
 #endif
 
+#ifndef DISABLE_FLOAT_API
+void downmix_float(const void *_x, float *sub, int subframe, int offset, int c1, int c2, int C)
+{
+   const float *x;
+   int j;
+   x = (const float *)_x;
+   for (j=0;j<subframe;j++)
+      sub[j] = x[(j+offset)*C+c1];
+   if (c2>-1)
+   {
+      for (j=0;j<subframe;j++)
+         sub[j] += x[(j+offset)*C+c2];
+   } else if (c2==-2)
+   {
+      int c;
+      for (c=1;c<C;c++)
+      {
+         for (j=0;j<subframe;j++)
+            sub[j] += x[(j+offset)*C+c];
+      }
+   }
+}
+#endif
+
+void downmix_int(const void *_x, float *sub, int subframe, int offset, int c1, int c2, int C)
+{
+   const opus_int16 *x;
+   int j;
+   x = (const opus_int16 *)_x;
+   for (j=0;j<subframe;j++)
+      sub[j] = x[(j+offset)*C+c1];
+   if (c2>-1)
+   {
+      for (j=0;j<subframe;j++)
+         sub[j] += x[(j+offset)*C+c2];
+   } else if (c2==-2)
+   {
+      int c;
+      for (c=1;c<C;c++)
+      {
+         for (j=0;j<subframe;j++)
+            sub[j] += x[(j+offset)*C+c];
+      }
+   }
+   for (j=0;j<subframe;j++)
+      sub[j] *= (1.f/32768);
+}
+
 opus_int32 frame_size_select(opus_int32 frame_size, int variable_duration, opus_int32 Fs)
 {
    int new_size;
@@ -883,11 +905,8 @@
 }
 
 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
-#ifndef FIXED_POINT
-                , AnalysisInfo *analysis_info
-#endif
-                )
+                unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+                const void *analysis_pcm, int c1, int c2, int analysis_channels, downmix_func downmix)
 {
     void *silk_enc;
     CELTEncoder *celt_enc;
@@ -916,6 +935,8 @@
     opus_int32 max_data_bytes; /* Max number of bytes we're allowed to use */
     int total_buffer;
     opus_val16 stereo_width;
+    const CELTMode *celt_mode;
+    AnalysisInfo analysis_info;
     VARDECL(opus_val16, tmp_prefill);
 
     ALLOC_STACK;
@@ -941,17 +962,35 @@
 
     lsb_depth = IMIN(lsb_depth, st->lsb_depth);
 
+    analysis_info.valid = 0;
+    celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
+#ifndef FIXED_POINT
+    if (st->silk_mode.complexity >= 7 && st->Fs==48000)
+    {
+       frame_size = run_analysis(&st->analysis, celt_mode, pcm, analysis_pcm,
+             frame_size, st->variable_duration, c1, c2, analysis_channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
+    } else
+#endif
+    {
+       frame_size = frame_size_select(frame_size, st->variable_duration, st->Fs);
+    }
+    if(frame_size<0)
+    {
+       return OPUS_BAD_ARG;
+    }
+
+
     st->voice_ratio = -1;
 
 #ifndef FIXED_POINT
     st->detected_bandwidth = 0;
-    if (analysis_info->valid)
+    if (analysis_info.valid)
     {
        int analysis_bandwidth;
        if (st->signal_type == OPUS_AUTO)
-          st->voice_ratio = (int)floor(.5+100*(1-analysis_info->music_prob));
+          st->voice_ratio = (int)floor(.5+100*(1-analysis_info.music_prob));
 
-       analysis_bandwidth = analysis_info->bandwidth;
+       analysis_bandwidth = analysis_info.bandwidth;
        if (analysis_bandwidth<=12)
           st->detected_bandwidth = OPUS_BANDWIDTH_NARROWBAND;
        else if (analysis_bandwidth<=14)
@@ -1310,11 +1349,9 @@
           /* When switching from SILK/Hybrid to CELT, only ask for a switch at the last frame */
           if (to_celt && i==nb_frames-1)
              st->user_forced_mode = MODE_CELT_ONLY;
-          tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50, tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth
-#ifndef FIXED_POINT
-                , analysis_info
-#endif
-                );
+          tmp_len = opus_encode_native(st, pcm+i*(st->channels*st->Fs/50), st->Fs/50,
+                tmp_data+i*bytes_per_frame, bytes_per_frame, lsb_depth,
+                analysis_pcm, c1, c2, analysis_channels, downmix);
           if (tmp_len<0)
           {
              RESTORE_STACK;
@@ -1476,9 +1513,7 @@
         if (prefill)
         {
             opus_int32 zero=0;
-            const CELTMode *celt_mode;
             int prefill_offset;
-            celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
             /* Use a smooth onset for the SILK prefill to avoid the encoder trying to encode
                a discontinuity. The exact location is what we need to avoid leaving any "gap"
                in the audio when mixing with the redundant CELT frame. Here we can afford to
@@ -1593,8 +1628,8 @@
                 if (st->variable_duration==OPUS_FRAMESIZE_VARIABLE && frame_size != st->Fs/50)
                 {
                    bonus = (60*st->stream_channels+40)*(st->Fs/frame_size-50);
-                   if (analysis_info->valid)
-                      bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info->tonality));
+                   if (analysis_info.valid)
+                      bonus = (opus_int32)(bonus*(1.f+.5f*analysis_info.tonality));
                 }
 #endif
                 celt_encoder_ctl(celt_enc, OPUS_SET_VBR(1));
@@ -1625,9 +1660,6 @@
     /* gain_fade() and stereo_fade() need to be after the buffer copying
        because we don't want any of this to affect the SILK part */
     if( st->prev_HB_gain < Q15ONE || HB_gain < Q15ONE ) {
-       const CELTMode *celt_mode;
-
-       celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
        gain_fade(pcm_buf, pcm_buf,
              st->prev_HB_gain, HB_gain, celt_mode->overlap, frame_size, st->channels, celt_mode->window, st->Fs);
     }
@@ -1638,9 +1670,6 @@
         /* Apply stereo width reduction (at low bitrates) */
         if( st->hybrid_stereo_width_Q14 < (1 << 14) || st->silk_mode.stereoWidth_Q14 < (1 << 14) ) {
             opus_val16 g1, g2;
-            const CELTMode *celt_mode;
-
-            celt_encoder_ctl(celt_enc, CELT_GET_MODE(&celt_mode));
             g1 = st->hybrid_stereo_width_Q14;
             g2 = (opus_val16)(st->silk_mode.stereoWidth_Q14);
 #ifdef FIXED_POINT
@@ -1699,7 +1728,7 @@
 
 #ifndef FIXED_POINT
     if (redundancy || st->mode != MODE_SILK_ONLY)
-       celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(analysis_info));
+       celt_encoder_ctl(celt_enc, CELT_SET_ANALYSIS(&analysis_info));
 #endif
 
     /* 5 ms redundant frame for CELT->SILK */
@@ -1843,7 +1872,7 @@
 
    for (i=0;i<frame_size*st->channels;i++)
       in[i] = FLOAT2INT16(pcm[i]);
-   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16);
+   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, pcm, 0, -2, st->channels, downmix_float);
    RESTORE_STACK;
    return ret;
 }
@@ -1857,7 +1886,7 @@
    {
       return OPUS_BAD_ARG;
    }
-   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16);
+   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 16, pcm, 0, -2, st->channels, downmix_int);
 }
 
 #else
@@ -1865,40 +1894,14 @@
       unsigned char *data, opus_int32 max_data_bytes)
 {
    int i, ret;
-   const CELTMode *celt_mode;
-   int delay_compensation;
-   int lsb_depth;
    VARDECL(float, in);
-   AnalysisInfo analysis_info;
    ALLOC_STACK;
 
-   opus_encoder_ctl(st, CELT_GET_MODE(&celt_mode));
-   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
-      delay_compensation = 0;
-   else
-      delay_compensation = st->delay_compensation;
-
-   lsb_depth = IMIN(16, st->lsb_depth);
-
-   analysis_info.valid = 0;
-   if (st->silk_mode.complexity >= 7 && st->Fs==48000)
-   {
-      frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm+st->channels*st->analysis.analysis_offset,
-            frame_size, st->variable_duration, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_int, &analysis_info);
-   } else {
-      frame_size = frame_size_select(frame_size, st->variable_duration, st->Fs);
-   }
-   if(frame_size<0)
-   {
-      RESTORE_STACK;
-      return OPUS_BAD_ARG;
-   }
-
    ALLOC(in, frame_size*st->channels, float);
 
    for (i=0;i<frame_size*st->channels;i++)
       in[i] = (1.0f/32768)*pcm[i];
-   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, &analysis_info);
+   ret = opus_encode_native(st, in, frame_size, data, max_data_bytes, 16, pcm, 0, -2, st->channels, downmix_int);
    RESTORE_STACK;
    return ret;
 }
@@ -1905,34 +1908,7 @@
 opus_int32 opus_encode_float(OpusEncoder *st, const float *pcm, int frame_size,
                       unsigned char *data, opus_int32 out_data_bytes)
 {
-   const CELTMode *celt_mode;
-   int delay_compensation;
-   int lsb_depth;
-   AnalysisInfo analysis_info;
-
-   opus_encoder_ctl(st, CELT_GET_MODE(&celt_mode));
-   if (st->application == OPUS_APPLICATION_RESTRICTED_LOWDELAY)
-      delay_compensation = 0;
-   else
-      delay_compensation = st->delay_compensation;
-
-   lsb_depth = IMIN(24, st->lsb_depth);
-
-   analysis_info.valid = 0;
-   if (st->silk_mode.complexity >= 7 && st->Fs==48000)
-   {
-      frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm+st->channels*st->analysis.analysis_offset,
-            frame_size, st->variable_duration, st->channels, st->Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix_float, &analysis_info);
-   } else {
-      frame_size = frame_size_select(frame_size, st->variable_duration, st->Fs);
-   }
-   if(frame_size<0)
-   {
-      return OPUS_BAD_ARG;
-   }
-
-   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, &analysis_info);
-
+   return opus_encode_native(st, pcm, frame_size, data, out_data_bytes, 24, pcm, 0, -2, st->channels, downmix_float);
 }
 #endif
 
--- a/src/opus_multistream_encoder.c
+++ b/src/opus_multistream_encoder.c
@@ -36,7 +36,6 @@
 #include <stdarg.h>
 #include "float_cast.h"
 #include "os_support.h"
-#include "analysis.h"
 #include "mathops.h"
 #include "mdct.h"
 #include "modes.h"
@@ -71,7 +70,6 @@
 );
 
 struct OpusMSEncoder {
-   TonalityAnalysisState analysis;
    ChannelLayout layout;
    int lfe_stream;
    int variable_duration;
@@ -409,7 +407,6 @@
    st->layout.nb_streams = streams;
    st->layout.nb_coupled_streams = coupled_streams;
    st->subframe_mem[0]=st->subframe_mem[1]=st->subframe_mem[2]=0;
-   OPUS_CLEAR(&st->analysis,1);
    if (!surround)
       st->lfe_stream = -1;
    st->bitrate_bps = OPUS_AUTO;
@@ -666,11 +663,8 @@
     int frame_size,
     unsigned char *data,
     opus_int32 max_data_bytes,
-    int lsb_depth
-#ifndef FIXED_POINT
-    , downmix_func downmix
-    , const void *pcm_analysis
-#endif
+    int lsb_depth,
+    downmix_func downmix
 )
 {
    opus_int32 Fs;
@@ -684,9 +678,6 @@
    unsigned char tmp_data[MS_FRAME_TMP];
    OpusRepacketizer rp;
    opus_int32 complexity;
-#ifndef FIXED_POINT
-   AnalysisInfo analysis_info;
-#endif
    const CELTMode *celt_mode;
    opus_int32 bitrates[256];
    opus_val16 bandLogE[42];
@@ -710,24 +701,6 @@
       RESTORE_STACK;
       return OPUS_BAD_ARG;
    }
-#ifndef FIXED_POINT
-   analysis_info.valid = 0;
-   if (complexity >= 7 && Fs==48000)
-   {
-      opus_int32 delay_compensation;
-      int channels;
-
-      channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
-      opus_encoder_ctl((OpusEncoder*)ptr, OPUS_GET_LOOKAHEAD(&delay_compensation));
-      delay_compensation -= Fs/400;
-
-      frame_size = run_analysis(&st->analysis, celt_mode, pcm, pcm_analysis,
-            frame_size, st->variable_duration, channels, Fs, st->bitrate_bps, delay_compensation, lsb_depth, downmix, &analysis_info);
-   } else
-#endif
-   {
-      frame_size = frame_size_select(frame_size, st->variable_duration, Fs);
-   }
    /* Validate frame_size before using it to allocate stack space.
       This mirrors the checks in opus_encode[_float](). */
    if (400*frame_size != Fs && 200*frame_size != Fs &&
@@ -783,6 +756,7 @@
       OpusEncoder *enc;
       int len;
       int curr_max;
+      int c1, c2;
 
       opus_repacketizer_init(&rp);
       enc = (OpusEncoder*)ptr;
@@ -805,6 +779,8 @@
                bandLogE[21+i] = bandSMR[21*right+i];
             }
          }
+         c1 = left;
+         c2 = right;
       } else {
          int i;
          int chan = get_mono_channel(&st->layout, s, -1);
@@ -816,6 +792,8 @@
             for (i=0;i<21;i++)
                bandLogE[i] = bandSMR[21*chan+i];
          }
+         c1 = chan;
+         c2 = -1;
       }
       if (st->surround)
          opus_encoder_ctl(enc, OPUS_SET_ENERGY_MASK(bandLogE));
@@ -824,11 +802,7 @@
       /* Reserve three bytes for the last stream and four for the others */
       curr_max -= IMAX(0,4*(st->layout.nb_streams-s-1)-1);
       curr_max = IMIN(curr_max,MS_FRAME_TMP);
-      len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth
-#ifndef FIXED_POINT
-            , &analysis_info
-#endif
-            );
+      len = opus_encode_native(enc, buf, frame_size, tmp_data, curr_max, lsb_depth, pcm, c1, c2, st->layout.nb_channels, downmix);
       if (len<0)
       {
          RESTORE_STACK;
@@ -901,7 +875,7 @@
 )
 {
    return opus_multistream_encode_native(st, opus_copy_channel_in_short,
-      pcm, frame_size, data, max_data_bytes, 16);
+      pcm, frame_size, data, max_data_bytes, 16, downmix_int);
 }
 
 #ifndef DISABLE_FLOAT_API
@@ -914,7 +888,7 @@
 )
 {
    return opus_multistream_encode_native(st, opus_copy_channel_in_float,
-      pcm, frame_size, data, max_data_bytes, 16);
+      pcm, frame_size, data, max_data_bytes, 16, downmix_float);
 }
 #endif
 
@@ -929,9 +903,8 @@
     opus_int32 max_data_bytes
 )
 {
-   int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
    return opus_multistream_encode_native(st, opus_copy_channel_in_float,
-      pcm, frame_size, data, max_data_bytes, 24, downmix_float, pcm+channels*st->analysis.analysis_offset);
+      pcm, frame_size, data, max_data_bytes, 24, downmix_float);
 }
 
 int opus_multistream_encode(
@@ -942,9 +915,8 @@
     opus_int32 max_data_bytes
 )
 {
-   int channels = st->layout.nb_streams + st->layout.nb_coupled_streams;
    return opus_multistream_encode_native(st, opus_copy_channel_in_short,
-      pcm, frame_size, data, max_data_bytes, 16, downmix_int, pcm+channels*st->analysis.analysis_offset);
+      pcm, frame_size, data, max_data_bytes, 16, downmix_int);
 }
 #endif
 
--- a/src/opus_private.h
+++ b/src/opus_private.h
@@ -82,9 +82,9 @@
 #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 *, float *, int, int, int);
-void downmix_float(const void *_x, float *sub, int subframe, int offset, int C);
-void downmix_int(const void *_x, float *sub, int subframe, int offset, int C);
+typedef void (*downmix_func)(const void *, float *, int, int, int, int, int);
+void downmix_float(const void *_x, float *sub, int subframe, int offset, int c1, int c2, int C);
+void downmix_int(const void *_x, float *sub, int subframe, int offset, int c1, int c2, int C);
 
 int optimize_framesize(const opus_val16 *x, int len, int C, opus_int32 Fs,
                 int bitrate, opus_val16 tonality, opus_val32 *mem, int buffering,
@@ -95,11 +95,8 @@
 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
-#ifndef FIXED_POINT
-                , AnalysisInfo *analysis_info
-#endif
-      );
+      unsigned char *data, opus_int32 out_data_bytes, int lsb_depth,
+      const void *analysis_pcm, int c1, int c2, int analysis_channels, downmix_func downmix);
 
 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,