/*
 * Function    : dtx_dec_amr_wb_reset
 */
int16 dtx_dec_amr_wb_reset(dtx_decState * st, const int16 isf_init[])
{
    int16 i;


    if (st == (dtx_decState *) NULL)
    {
        /* dtx_dec_amr_wb_reset invalid parameter */
        return (-1);
    }
    st->since_last_sid = 0;
    st->true_sid_period_inv = (1 << 13);      /* 0.25 in Q15 */

    st->log_en = 3500;
    st->old_log_en = 3500;
    /* low level noise for better performance in  DTX handover cases */

    st->cng_seed = RANDOM_INITSEED;

    st->hist_ptr = 0;

    /* Init isf_hist[] and decoder log frame energy */
    pv_memcpy((void *)st->isf, (void *)isf_init, M*sizeof(*isf_init));

    pv_memcpy((void *)st->isf_old, (void *)isf_init, M*sizeof(*isf_init));

    for (i = 0; i < DTX_HIST_SIZE; i++)
    {
        pv_memcpy((void *)&st->isf_hist[i * M], (void *)isf_init, M*sizeof(*isf_init));
        st->log_en_hist[i] = st->log_en;
    }

    st->dtxHangoverCount = DTX_HANG_CONST;
    st->decAnaElapsedCount = 32767;

    st->sid_frame = 0;
    st->valid_data = 0;
    st->dtxHangoverAdded = 0;

    st->dtxGlobalState = SPEECH;
    st->data_updated = 0;

    st->dither_seed = RANDOM_INITSEED;
    st->CN_dith = 0;

    return 0;
}
Beispiel #2
0
void sbr_open(Int32 sampleRate,
              SBR_DEC *sbrDec,
              SBRDECODER_DATA * self,
              Bool bDownSampledSbr)

{
    Int16 i ;

    SBR_CHANNEL *SbrChannel;


    SbrChannel = self->SbrChannel;

    for (i = 0; i < MAX_NUM_CHANNELS; i++)
    {
        pv_memset((void *)&(SbrChannel[i]),
                  0,
                  sizeof(SBR_CHANNEL));

        /* init a default header such that we can at least do upsampling later */

        pv_memcpy(&(SbrChannel[i].frameData.sbr_header),
                  &defaultHeader,
                  sizeof(SBR_HEADER_DATA));

        /* should be handled by sample rate mode bit */
        if (sampleRate > 24000 || bDownSampledSbr)
        {
            SbrChannel[i].frameData.sbr_header.sampleRateMode = SINGLE_RATE;
        }


        SbrChannel[i].outFrameSize =
            init_sbr_dec(sampleRate,
                         self->SbrChannel[0].frameData.sbr_header.sampleRateMode,
                         sbrDec,
                         &(SbrChannel[i].frameData));

        SbrChannel[i].syncState     = UPSAMPLING;

        SbrChannel[i].frameData.sUp = 1;        /* reset mode */
    }
}
/*
 * Function    : dtx_dec_amr_wb
 */
int16 dtx_dec_amr_wb(
    dtx_decState * st,                    /* i/o : State struct         */
    int16 * exc2,                        /* o   : CN excitation        */
    int16 new_state,                     /* i   : New DTX state        */
    int16 isf[],                         /* o   : CN ISF vector        */
    int16 ** prms
)
{
    int16 log_en_index;
    int16 ind[7];
    int16 i, j;
    int16 int_fac;
    int16 gain;

    int32 L_isf[M], L_log_en_int, level32, ener32;
    int16 ptr;
    int16 tmp_int_length;
    int16 tmp, exp, exp0, log_en_int_e, log_en_int_m, level;

    /* This function is called if synthesis state is not SPEECH the globally passed  inputs to this function
     * are st->sid_frame st->valid_data st->dtxHangoverAdded new_state  (SPEECH, DTX, DTX_MUTE) */

    if ((st->dtxHangoverAdded != 0) &&
            (st->sid_frame != 0))
    {
        /* sid_first after dtx hangover period */
        /* or sid_upd after dtxhangover        */

        /* consider  twice the last frame */
        ptr = st->hist_ptr + 1;

        if (ptr == DTX_HIST_SIZE)
            ptr = 0;

        pv_memcpy((void *)&st->isf_hist[ptr * M], (void *)&st->isf_hist[st->hist_ptr * M], M*sizeof(*st->isf_hist));

        st->log_en_hist[ptr] = st->log_en_hist[st->hist_ptr];

        /* compute mean log energy and isf from decoded signal (SID_FIRST) */
        st->log_en = 0;
        for (i = 0; i < M; i++)
        {
            L_isf[i] = 0;
        }

        /* average energy and isf */
        for (i = 0; i < DTX_HIST_SIZE; i++)
        {
            /* Division by DTX_HIST_SIZE = 8 has been done in dtx_buffer log_en is in Q10 */
            st->log_en = add_int16(st->log_en, st->log_en_hist[i]);

            for (j = 0; j < M; j++)
            {
                L_isf[j] = add_int32(L_isf[j], (int32)(st->isf_hist[i * M + j]));
            }
        }

        /* st->log_en in Q9 */
        st->log_en >>=  1;

        /* Add 2 in Q9, in order to have only positive values for Pow2 */
        /* this value is subtracted back after Pow2 function */
        st->log_en += 1024;

        if (st->log_en < 0)
            st->log_en = 0;

        for (j = 0; j < M; j++)
        {
            st->isf[j] = (int16)(L_isf[j] >> 3);  /* divide by 8 */
        }

    }
SBR_ERROR sbr_read_data(SBRDECODER_DATA * self,
                        SBR_DEC * sbrDec,
                        SBRBITSTREAM *stream)
{
    SBR_ERROR sbr_err =  SBRDEC_OK;
    int32_t SbrFrameOK = 1;
    int32_t sbrCRCAlwaysOn = 0;

    UInt32 bs_header_flag = 0;

    SBR_HEADER_STATUS headerStatus = HEADER_OK;

    SBR_CHANNEL *SbrChannel = self->SbrChannel;

    int32_t zeropadding_bits;

    BIT_BUFFER bitBuf ;

    /*
     *  evaluate Bitstream
     */

    bitBuf.buffer_word    = 0;
    bitBuf.buffered_bits  = 0;
    bitBuf.nrBitsRead     = 0;

    bitBuf.char_ptr  =  stream->sbrElement[0].Data;
    bitBuf.bufferLen = (stream->sbrElement[0].Payload) << 3;


    /*
     *  we have to skip a nibble because the first element of Data only
     *  contains a nibble of data !
     */
    buf_getbits(&bitBuf, LEN_NIBBLE);

    if ((stream->sbrElement[0].ExtensionType == SBR_EXTENSION_CRC) ||
            sbrCRCAlwaysOn)
    {
        int32_t CRCLen = ((stream->sbrElement[0].Payload - 1) << 3) + 4 - SI_SBR_CRC_BITS;
        SbrFrameOK = sbr_crc_check(&bitBuf, CRCLen);
    }


    if (SbrFrameOK)
    {
        /*
         *  The sbr data seems ok, if the header flag is set we read the header
         *  and check if vital parameters have changed since the previous frame.
         *  If the syncState equals UPSAMPLING, the SBR Tool has not been
         *  initialised by SBR header data, and can only do upsampling
         */

        bs_header_flag = buf_getbits(&bitBuf, 1);  /* read Header flag */

        if (bs_header_flag)
        {
            /*
             *  If syncState == SBR_ACTIVE, it means that we've had a SBR header
             *  before, and we will compare with the previous header to see if a
             *  reset is required. If the syncState equals UPSAMPLING this means
             *  that the SBR-Tool so far is only initialised to do upsampling
             *  and hence we need to do a reset, and initialise the system
             *  according to the present header.
             */

            headerStatus = sbr_get_header_data(&(SbrChannel[0].frameData.sbr_header),
                                               &bitBuf,
                                               SbrChannel[0].syncState);
        }     /* if (bs_header_flag) */


        switch (stream->sbrElement[0].ElementID)
        {
            case SBR_ID_SCE :

                /* change of control data, reset decoder */
                if (headerStatus == HEADER_RESET)
                {
                    sbr_err = sbr_reset_dec(&(SbrChannel[0].frameData),
                                            sbrDec,
                                            self->SbrChannel[0].frameData.sbr_header.sampleRateMode);

                    if (sbr_err != SBRDEC_OK)
                    {
                        break;
                    }
                    /*
                     * At this point we have a header and the system has been reset,
                     * hence syncState from now on will be SBR_ACTIVE.
                     */
                    SbrChannel[0].syncState     = SBR_ACTIVE;
                }

                if ((SbrChannel[0].syncState == SBR_ACTIVE))
                {
                    sbr_err = sbr_get_sce(&(SbrChannel[0].frameData),
                                          &bitBuf
#ifdef PARAMETRICSTEREO
                                          , self->hParametricStereoDec
#endif
                                         );

                    if (sbr_err != SBRDEC_OK)
                    {
                        break;
                    }
                }

                break;

            case SBR_ID_CPE :

                if (bs_header_flag)
                {
                    pv_memcpy(&(SbrChannel[1].frameData.sbr_header),
                              &(SbrChannel[0].frameData.sbr_header),
                              sizeof(SBR_HEADER_DATA));
                }

                /* change of control data, reset decoder */
                if (headerStatus == HEADER_RESET)
                {
                    for (int32_t lr = 0 ; lr < 2 ; lr++)
                    {
                        sbr_err = sbr_reset_dec(&(SbrChannel[lr].frameData),
                                                sbrDec,
                                                self->SbrChannel[0].frameData.sbr_header.sampleRateMode);

                        if (sbr_err != SBRDEC_OK)
                        {
                            break;
                        }

                        SbrChannel[lr].syncState = SBR_ACTIVE;
                    }
                }

                if (SbrChannel[0].syncState == SBR_ACTIVE)
                {
                    sbr_err = sbr_get_cpe(&(SbrChannel[0].frameData),
                                          &(SbrChannel[1].frameData),
                                          &bitBuf);

                    if (sbr_err != SBRDEC_OK)
                    {
                        break;
                    }

                }
                break;

            default:
                sbr_err = SBRDEC_ILLEGAL_PLUS_ELE_ID;
                break;
        }

    }           /* if (SbrFrameOK) */

    /*
     *  Check that the bits read did not go beyond SBR frame boundaries
     */

    zeropadding_bits = (8 - (bitBuf.nrBitsRead & 0x7)) & 0x7;

    if ((bitBuf.nrBitsRead + zeropadding_bits)  > bitBuf.bufferLen)
    {
        sbr_err = SBRDEC_INVALID_BITSTREAM;
    }

    return sbr_err;
}
SBR_ERROR extractFrameInfo(BIT_BUFFER     * hBitBuf,
                           SBR_FRAME_DATA * h_frame_data)
{

    Int32 absBordLead = 0;
    Int32 nRelLead = 0;
    Int32 nRelTrail = 0;
    Int32 bs_num_env = 0;
    Int32 bs_num_rel = 0;
    Int32 bs_var_bord = 0;
    Int32 bs_var_bord_0 = 0;
    Int32 bs_var_bord_1 = 0;
    Int32 bs_pointer = 0;
    Int32 bs_pointer_bits;
    Int32 frameClass;
    Int32 temp;
    Int32 env;
    Int32 k;
    Int32 bs_num_rel_0 = 0;
    Int32 bs_num_rel_1 = 0;
    Int32 absBordTrail = 0;
    Int32 middleBorder = 0;
    Int32 bs_num_noise;
    Int32 lA = 0;

    Int32 tE[MAX_ENVELOPES + 1];
    Int32 tQ[2 + 1];
    Int32 f[MAX_ENVELOPES + 1];
    Int32 bs_rel_bord[3];
    Int32 bs_rel_bord_0[3];
    Int32 bs_rel_bord_1[3];
    Int32 relBordLead[3];
    Int32 relBordTrail[3];


    Int32 *v_frame_info = h_frame_data->frameInfo;

    SBR_ERROR err =  SBRDEC_OK;


    /*
     * First read from the bitstream.
     */

    /* Read frame class */
    h_frame_data->frameClass = frameClass = buf_getbits(hBitBuf, SBR_CLA_BITS);


    switch (frameClass)
    {

        case FIXFIX:
            temp = buf_getbits(hBitBuf, SBR_ENV_BITS);   /* 2 bits */

            bs_num_env = 1 << temp;


            f[0] = buf_getbits(hBitBuf, SBR_RES_BITS);   /* 1 bit */

            for (env = 1; env < bs_num_env; env++)
            {
                f[env] = f[0];
            }

            nRelLead     = bs_num_env - 1;
            absBordTrail  = 16;


            break;

        case FIXVAR:
            bs_var_bord = buf_getbits(hBitBuf, SBR_ABS_BITS);   /* 2 bits */
            bs_num_rel  = buf_getbits(hBitBuf, SBR_NUM_BITS);   /* 2 bits */
            bs_num_env  = bs_num_rel + 1;

            for (k = 0; k < bs_num_env - 1; k++)
            {
                bs_rel_bord[k] = (buf_getbits(hBitBuf, SBR_REL_BITS) + 1) << 1;
            }

            bs_pointer_bits = bs_pointer_bits_tbl[bs_num_env];

            bs_pointer = buf_getbits(hBitBuf, bs_pointer_bits);

            for (env = 0; env < bs_num_env; env++)
            {                                                    /* 1 bit */
                f[bs_num_env - 1 - env] = buf_getbits(hBitBuf, SBR_RES_BITS);
            }

            absBordTrail  = 16 + bs_var_bord;
            nRelTrail     = bs_num_rel;

            break;

        case VARFIX:
            bs_var_bord = buf_getbits(hBitBuf, SBR_ABS_BITS);   /* 2 bits */
            bs_num_rel  = buf_getbits(hBitBuf, SBR_NUM_BITS);   /* 2 bits */
            bs_num_env  = bs_num_rel + 1;

            for (k = 0; k < bs_num_env - 1; k++)
            {
                bs_rel_bord[k] = (buf_getbits(hBitBuf, SBR_REL_BITS) + 1) << 1;
            }

            bs_pointer_bits = bs_pointer_bits_tbl[bs_num_env];

            bs_pointer = buf_getbits(hBitBuf, bs_pointer_bits);

            for (env = 0; env < bs_num_env; env++)
            {                                  /* 1 bit */
                f[env] = buf_getbits(hBitBuf, SBR_RES_BITS);
            }

            absBordTrail = 16;
            absBordLead  = bs_var_bord;
            nRelLead     = bs_num_rel;

            break;

        case VARVAR:
            bs_var_bord_0 = buf_getbits(hBitBuf, SBR_ABS_BITS);   /* 2 bits */
            bs_var_bord_1 = buf_getbits(hBitBuf, SBR_ABS_BITS);
            bs_num_rel_0  = buf_getbits(hBitBuf, SBR_NUM_BITS);   /* 2 bits */
            bs_num_rel_1  = buf_getbits(hBitBuf, SBR_NUM_BITS);

            bs_num_env = bs_num_rel_0 + bs_num_rel_1 + 1;

            for (k = 0; k < bs_num_rel_0; k++)
            {                                                 /* 2 bits */
                bs_rel_bord_0[k] = (buf_getbits(hBitBuf, SBR_REL_BITS) + 1) << 1;
            }

            for (k = 0; k < bs_num_rel_1; k++)
            {                                                 /* 2 bits */
                bs_rel_bord_1[k] = (buf_getbits(hBitBuf, SBR_REL_BITS) + 1) << 1;
            }


            bs_pointer_bits = bs_pointer_bits_tbl[bs_num_env];

            bs_pointer = buf_getbits(hBitBuf, bs_pointer_bits);

            for (env = 0; env < bs_num_env; env++)
            {                                  /* 1 bit */
                f[env] = buf_getbits(hBitBuf, SBR_RES_BITS);
            }

            absBordLead   = bs_var_bord_0;
            absBordTrail  = 16 + bs_var_bord_1;
            nRelLead      = bs_num_rel_0;
            nRelTrail     = bs_num_rel_1;

            break;

    };


    /*
     * Calculate the framing.
     */


    switch (frameClass)
    {
        case FIXFIX:
            for (k = 0; k < nRelLead; k++)
            {
                relBordLead[k] = T_16_ov_bs_num_env_tbl[bs_num_env];
            }
            break;
        case VARFIX:
            for (k = 0; k < nRelLead; k++)
            {
                relBordLead[k] = bs_rel_bord[k];
            }
            break;
        case VARVAR:
            for (k = 0; k < nRelLead; k++)
            {
                relBordLead[k] = bs_rel_bord_0[k];
            }
            for (k = 0; k < nRelTrail; k++)
            {
                relBordTrail[k] = bs_rel_bord_1[k];
            }
            break;
        case FIXVAR:
            for (k = 0; k < nRelTrail; k++)
            {
                relBordTrail[k] = bs_rel_bord[k];
            }
            break;
    }


    tE[0]          = absBordLead;
    tE[bs_num_env] = absBordTrail;

    for (env = 1; env <= nRelLead; env++)
    {
        tE[env] = absBordLead;
        for (k = 0; k <= env - 1; k++)
        {
            tE[env] += relBordLead[k];
        }
    }

    for (env = nRelLead + 1; env < bs_num_env; env++)
    {
        tE[env] = absBordTrail;
        for (k = 0; k <= bs_num_env - env - 1; k++)
        {
            tE[env] -= relBordTrail[k];
        }
    }



    switch (frameClass)
    {
        case  FIXFIX:
            middleBorder = bs_num_env >> 1;
            break;
        case VARFIX:
            switch (bs_pointer)
            {
                case 0:
                    middleBorder = 1;
                    break;
                case 1:
                    middleBorder = bs_num_env - 1;
                    break;
                default:
                    middleBorder = bs_pointer - 1;
                    break;
            };
            break;
        case FIXVAR:
        case VARVAR:
            switch (bs_pointer)
            {
                case 0:
                case 1:
                    middleBorder = bs_num_env - 1;
                    break;
                default:
                    middleBorder = bs_num_env + 1 - bs_pointer;
                    break;
            };
            break;
    };


    tQ[0] = tE[0];
    if (bs_num_env > 1)
    {
        tQ[1] = tE[middleBorder];
        tQ[2] = tE[bs_num_env];
        bs_num_noise = 2;
    }
    else
    {
        tQ[1] = tE[bs_num_env];
        bs_num_noise = 1;
    }

    /*
     *  Check consistency on freq bands
     */

    if ((tE[bs_num_env] < tE[0]) || (tE[0] < 0))
    {
        err = SBRDEC_INVALID_BITSTREAM;
    }


    switch (frameClass)
    {
        case  FIXFIX:
            lA = -1;
            break;
        case VARFIX:
            switch (bs_pointer)
            {
                case 0:
                case 1:
                    lA = -1;
                    break;
                default:
                    lA = bs_pointer - 1;
                    break;
            };
            break;
        case FIXVAR:
        case VARVAR:
            switch (bs_pointer)
            {
                case 0:
                    lA = - 1;
                    break;
                default:
                    lA = bs_num_env + 1 - bs_pointer;
                    break;
            };
            break;
    };

    /*
     * Build the frameInfo vector...
     */

    v_frame_info[0] = bs_num_env;   /* Number of envelopes*/
    pv_memcpy(v_frame_info + 1, tE, (bs_num_env + 1)*sizeof(Int32));    /* time borders*/
    /* frequency resolution */
    pv_memcpy(v_frame_info + 1 + bs_num_env + 1, f, bs_num_env*sizeof(Int32));

    temp = (1 + bs_num_env) << 1;
    v_frame_info[temp] = lA;                     /* transient envelope*/
    v_frame_info[temp + 1] = bs_num_noise;       /* Number of noise envelopes */
    /* noise borders */
    pv_memcpy(v_frame_info + temp + 2, tQ, (bs_num_noise + 1)*sizeof(Int32));


    return (err);

}
SBR_ERROR sbr_get_cpe(SBR_FRAME_DATA * hFrameDataLeft,
                      SBR_FRAME_DATA * hFrameDataRight,
                      BIT_BUFFER  * hBitBuf)
{
    Int32 i;
    Int32 bits;
    SBR_ERROR err =  SBRDEC_OK;

    /* reserved bits */
    bits = buf_getbits(hBitBuf, SI_SBR_RESERVED_PRESENT);

    if (bits)
    {
        buf_getbits(hBitBuf, SI_SBR_RESERVED_BITS_DATA);
        buf_getbits(hBitBuf, SI_SBR_RESERVED_BITS_DATA);
    }

    /* Read coupling flag */
    bits = buf_getbits(hBitBuf, SI_SBR_COUPLING_BITS);

    if (bits)
    {
        hFrameDataLeft->coupling = COUPLING_LEVEL;
        hFrameDataRight->coupling = COUPLING_BAL;
    }
    else
    {
        hFrameDataLeft->coupling = COUPLING_OFF;
        hFrameDataRight->coupling = COUPLING_OFF;
    }


    err = extractFrameInfo(hBitBuf, hFrameDataLeft);

    if (err != SBRDEC_OK)
    {
        return err;
    }

    if (hFrameDataLeft->coupling)
    {

        pv_memcpy(hFrameDataRight->frameInfo,
                  hFrameDataLeft->frameInfo,
                  LENGTH_FRAME_INFO * sizeof(Int32));

        hFrameDataRight->nNoiseFloorEnvelopes = hFrameDataLeft->nNoiseFloorEnvelopes;
        hFrameDataRight->frameClass = hFrameDataLeft->frameClass;


        sbr_get_dir_control_data(hFrameDataLeft, hBitBuf);
        sbr_get_dir_control_data(hFrameDataRight, hBitBuf);

        for (i = 0; i < hFrameDataLeft->nNfb; i++)
        {
            hFrameDataLeft->sbr_invf_mode_prev[i]  = hFrameDataLeft->sbr_invf_mode[i];
            hFrameDataRight->sbr_invf_mode_prev[i] = hFrameDataRight->sbr_invf_mode[i];

            hFrameDataLeft->sbr_invf_mode[i]  = (INVF_MODE) buf_getbits(hBitBuf, SI_SBR_INVF_MODE_BITS);
            hFrameDataRight->sbr_invf_mode[i] = hFrameDataLeft->sbr_invf_mode[i];
        }

        sbr_get_envelope(hFrameDataLeft, hBitBuf);
        sbr_get_noise_floor_data(hFrameDataLeft, hBitBuf);
        sbr_get_envelope(hFrameDataRight, hBitBuf);

    }
    else
    {
        err = extractFrameInfo(hBitBuf, hFrameDataRight);

        if (err != SBRDEC_OK)
        {
            return err;
        }


        sbr_get_dir_control_data(hFrameDataLeft,  hBitBuf);
        sbr_get_dir_control_data(hFrameDataRight, hBitBuf);

        for (i = 0; i <  hFrameDataLeft->nNfb; i++)
        {
            hFrameDataLeft->sbr_invf_mode_prev[i]  = hFrameDataLeft->sbr_invf_mode[i];
            hFrameDataLeft->sbr_invf_mode[i]  =
                (INVF_MODE) buf_getbits(hBitBuf, SI_SBR_INVF_MODE_BITS);
        }

        for (i = 0; i <  hFrameDataRight->nNfb; i++)
        {
            hFrameDataRight->sbr_invf_mode_prev[i] = hFrameDataRight->sbr_invf_mode[i];

            hFrameDataRight->sbr_invf_mode[i] =
                (INVF_MODE) buf_getbits(hBitBuf, SI_SBR_INVF_MODE_BITS);
        }
        sbr_get_envelope(hFrameDataLeft,  hBitBuf);
        sbr_get_envelope(hFrameDataRight, hBitBuf);

        sbr_get_noise_floor_data(hFrameDataLeft,  hBitBuf);

    }

    sbr_get_noise_floor_data(hFrameDataRight, hBitBuf);

    pv_memset((void *)hFrameDataLeft->addHarmonics,
              0,
              hFrameDataLeft->nSfb[HI]*sizeof(Int32));

    pv_memset((void *)hFrameDataRight->addHarmonics,
              0,
              hFrameDataRight->nSfb[HI]*sizeof(Int32));

    sbr_get_additional_data(hFrameDataLeft, hBitBuf);
    sbr_get_additional_data(hFrameDataRight, hBitBuf);

    sbr_extract_extended_data(hBitBuf
// 2010.01.26 : 
// in order to detect ps tag in adts/adif but decoding it
// we remove this definition
////#ifdef PARAMETRICSTEREO
                              , NULL
////#endif
                             );

    return SBRDEC_OK;

}
SBR_HEADER_STATUS sbr_get_header_data(SBR_HEADER_DATA   * h_sbr_header,
                                      BIT_BUFFER          * hBitBuf,
                                      SBR_SYNC_STATE     syncState)
{
    SBR_HEADER_DATA lastHeader;
    Int32 headerExtra1, headerExtra2;


    /* Copy header to temporary header */
    if (syncState == SBR_ACTIVE)
    {
        pv_memcpy(&lastHeader, h_sbr_header, sizeof(SBR_HEADER_DATA));
    }
    else
    {
        pv_memset((void *)&lastHeader, 0, sizeof(SBR_HEADER_DATA));
    }


    /* Read new header from bitstream */
    h_sbr_header->ampResolution   = buf_getbits(hBitBuf, SI_SBR_AMP_RES_BITS);
    h_sbr_header->startFreq       = buf_getbits(hBitBuf, SI_SBR_START_FREQ_BITS);
    h_sbr_header->stopFreq        = buf_getbits(hBitBuf, SI_SBR_STOP_FREQ_BITS);
    h_sbr_header->xover_band      = buf_getbits(hBitBuf, SI_SBR_XOVER_BAND_BITS);

    buf_getbits(hBitBuf, SI_SBR_RESERVED_BITS_HDR);

    headerExtra1    = buf_getbits(hBitBuf, SI_SBR_HEADER_EXTRA_1_BITS);
    headerExtra2    = buf_getbits(hBitBuf, SI_SBR_HEADER_EXTRA_2_BITS);

    /* handle extra header information */
    if (headerExtra1)
    {
        h_sbr_header->freqScale   = buf_getbits(hBitBuf, SI_SBR_FREQ_SCALE_BITS);
        h_sbr_header->alterScale  = buf_getbits(hBitBuf, SI_SBR_ALTER_SCALE_BITS);
        h_sbr_header->noise_bands = buf_getbits(hBitBuf, SI_SBR_NOISE_BANDS_BITS);
    }
    else
    { /* Set default values.*/
        h_sbr_header->freqScale   = SBR_FREQ_SCALE_DEFAULT;
        h_sbr_header->alterScale  = SBR_ALTER_SCALE_DEFAULT;
        h_sbr_header->noise_bands = SBR_NOISE_BANDS_DEFAULT;
    }


    if (headerExtra2)
    {
        h_sbr_header->limiterBands    = buf_getbits(hBitBuf, SI_SBR_LIMITER_BANDS_BITS);
        h_sbr_header->limiterGains    = buf_getbits(hBitBuf, SI_SBR_LIMITER_GAINS_BITS);
        h_sbr_header->interpolFreq    = buf_getbits(hBitBuf, SI_SBR_INTERPOL_FREQ_BITS);
        h_sbr_header->smoothingLength = buf_getbits(hBitBuf, SI_SBR_SMOOTHING_LENGTH_BITS);
    }
    else
    { /* Set default values.*/
        h_sbr_header->limiterBands    = SBR_LIMITER_BANDS_DEFAULT;
        h_sbr_header->limiterGains    = SBR_LIMITER_GAINS_DEFAULT;
        h_sbr_header->interpolFreq    = SBR_INTERPOL_FREQ_DEFAULT;
        h_sbr_header->smoothingLength = SBR_SMOOTHING_LENGTH_DEFAULT;
    }

    if (syncState == SBR_ACTIVE)
    {
        h_sbr_header->status = HEADER_OK;

        /* look for new settings */
        if (lastHeader.startFreq   != h_sbr_header->startFreq   ||
                lastHeader.stopFreq    != h_sbr_header->stopFreq    ||
                lastHeader.xover_band  != h_sbr_header->xover_band  ||
                lastHeader.freqScale   != h_sbr_header->freqScale   ||
                lastHeader.alterScale  != h_sbr_header->alterScale  ||
                lastHeader.noise_bands != h_sbr_header->noise_bands)
        {
            h_sbr_header->status = HEADER_RESET;
        }
    }
    else
    {
        h_sbr_header->status = HEADER_RESET;
    }

    return h_sbr_header->status;
}
Int get_prog_config(
    tDec_Int_File *pVars,
    ProgConfig    *pScratchPCE)
{
    Int    i;
    UInt   tag;
    Int    numChars;
    UInt   temp;
    Bool   flag;
    Int    status          = SUCCESS;
    BITS   *pInputStream   = &(pVars->inputStream);


    /*
     * The tag is used at the very end to see if this PCE is
     * the one to be used. Otherwise it does not need to be saved for the
     * the simple configurations to be used in this version of an AAC
     * decoder.
     *
     * All of the bits of this PCE must be read even if this PCE will not
     * be used. They are read into a temporary PCE, then later it is decided
     * whether to keep this PCE.
     *
     * To allow quick removal of the fields from the ProgConfig structure
     * that will probably not be used at a later date,
     * while still advancing the bitstream pointer,the return value of
     * getbits is saved into a temporary variable, then transfered to
     * the structure item.
     */
    tag = get9_n_lessbits(LEN_TAG, pInputStream);

    pScratchPCE->profile = get9_n_lessbits(LEN_PROFILE, pInputStream);

    pScratchPCE->sampling_rate_idx = get9_n_lessbits(LEN_SAMP_IDX, pInputStream);

    if (!pVars->adif_test && (pScratchPCE->sampling_rate_idx != pVars->prog_config.sampling_rate_idx))
    {
#ifdef AAC_PLUS
        /*
         *  PCE carries the baseline frequency, if SBR or PS are used, the frequencies will not match
         *  so check for this unique case, and let decoding continue if this is a redundant PCE
         */
        if ((pScratchPCE->sampling_rate_idx != (pVars->prog_config.sampling_rate_idx + 3)) ||
                (pVars->mc_info.upsamplingFactor != 2))
#endif
        {
            /* rewind the pointer as implicit channel configuration maybe the case */
            pInputStream->usedBits -= (LEN_TAG + LEN_PROFILE + LEN_SAMP_IDX);

            return (1); /*  mismatch cannot happen */
        }
    }


    /*
     * Retrieve the number of element lists for each of
     * front, side, back, lfe, data, and coupling.
     *
     * For two-channel stereo or mono, only the data in the front needs
     * to be saved. However, ALL fields need to be skipped over in some
     * fashion. Also, the number of elements needs to be temporarily saved
     * to call get_ele_list(). If that function was changed to pass in
     * the number of points to be read, the memory set aside inside the
     * ProgConfig structure could be removed.
     */

    /*
     * The next six function calls could be combined into one, then use
     * shifts and masks to retrieve the individual fields.
     */
    temp = get9_n_lessbits(LEN_NUM_ELE, pInputStream);

    pScratchPCE->front.num_ele = temp;

    /* Needed only to read in the element list. */
    temp = get9_n_lessbits(LEN_NUM_ELE, pInputStream);

    pScratchPCE->side.num_ele = temp;

    /* Needed only to read in the element list. */
    temp = get9_n_lessbits(LEN_NUM_ELE, pInputStream);

    pScratchPCE->back.num_ele = temp;

    /* Needed only to read in the element list. */
    temp = get9_n_lessbits(LEN_NUM_LFE, pInputStream);

    pScratchPCE->lfe.num_ele = temp;

    /* Needed only to read in the element list. */
    temp = get9_n_lessbits(LEN_NUM_DAT, pInputStream);
    pScratchPCE->data.num_ele = temp;

    /* Needed only to read in the element list. */
    temp = get9_n_lessbits(LEN_NUM_CCE, pInputStream);

    pScratchPCE->coupling.num_ele = temp;

    /*
     * Read in mix down data.
     *
     * Whether these fields can be removed and have proper operation
     * will be determined at a later date.
     */

    /* Read presence of mono_mix */
    flag = get1bits(pInputStream);/* LEN_MIX_PRES,*/

    pScratchPCE->mono_mix.present = flag;

    if (flag != FALSE)
    {
        temp = get9_n_lessbits(LEN_TAG, pInputStream);

        pScratchPCE->mono_mix.ele_tag = temp;

    } /* end if (flag != FALSE) */

    /* Read presence of stereo mix */
    flag = get1bits(pInputStream);   /* LEN_MIX_PRES,*/

    pScratchPCE->stereo_mix.present = flag;

    if (flag != FALSE)
    {
        temp = get9_n_lessbits(LEN_TAG, pInputStream);

        pScratchPCE->stereo_mix.ele_tag = temp;

    } /* end if (flag != FALSE) */

    /* Read presence of matrix mix */
    flag = get1bits(pInputStream);  /* LEN_MIX_PRES,*/

    pScratchPCE->matrix_mix.present = flag;

    if (flag != FALSE)
    {
        temp = get9_n_lessbits(LEN_MMIX_IDX, pInputStream);

        pScratchPCE->matrix_mix.ele_tag = temp;

        temp = get1bits(pInputStream);  /* LEN_PSUR_ENAB,*/

        pScratchPCE->matrix_mix.pseudo_enab = temp;

    } /* end if (flag != FALSE) */

    /*
     * Get each of the element lists. Only the front information will be
     * used for the PV decoder, but the usedBits field of pInputStream must
     * be advanced appropriately.
     *
     * This could be optimized by advancing the bit stream for the
     * elements that do not need to be read.
     */
    get_ele_list(&pScratchPCE->front,
                 pInputStream,
                 TRUE);

    get_ele_list(&pScratchPCE->side,
                 pInputStream,
                 TRUE);

    get_ele_list(&pScratchPCE->back,
                 pInputStream,
                 TRUE);

    get_ele_list(&pScratchPCE->lfe,
                 pInputStream,
                 FALSE);

    get_ele_list(&pScratchPCE->data,
                 pInputStream,
                 FALSE);

    get_ele_list(&pScratchPCE->coupling,
                 pInputStream,
                 TRUE);

    /*
     * The standard requests a byte alignment before reading in the
     * comment. This can be done because LEN_COMMENT_BYTES == 8.
     */
    byte_align(pInputStream);

    numChars = get9_n_lessbits(LEN_COMMENT_BYTES, pInputStream);

    /*
     * Ignore the comment - it requires 65 bytes to store (or worse on DSP).
     * If this field is restored, make sure to append a trailing '\0'
     */
    for (i = numChars; i > 0; i--)
    {
        pScratchPCE->comments[i] = (Char) get9_n_lessbits(LEN_BYTE,
                                   pInputStream);

    } /* end for */


    if (pVars->current_program < 0)
    {
        /*
         * If this is the first PCE, it becomes the current, regardless of
         * its tag number.
         */
        pVars->current_program = tag;

        pVars->mc_info.ch_info[0].tag = 0;

    } /* end if (pVars->current_program < 0) */


    if (tag == (UInt)pVars->current_program)
    {
        /*
         * This branch is reached under two conditions:
         * 1) This is the first PCE found, it was selected in the above if
         *    block. In all encoders found thus far, the tag value has been
         *    zero.
         * 2) A PCE has been sent by the encoder with a tag that matches the
         *    the first one sent. It will then be re-read. No encoder found
         *
         * Regardless, the temporary PCE will now be copied into the
         * the one official program configuration.
         */

        /*
         *  Keep adts setting in case of a redundant PCE (only applicable when
         *  using aac-lib own adts parser)
         */
        pScratchPCE->file_is_adts = pVars->prog_config.file_is_adts;
        pScratchPCE->headerless_frames = pVars->prog_config.headerless_frames;

        pv_memcpy(&pVars->prog_config,
                  pScratchPCE,
                  sizeof(ProgConfig));


        tag = 0;

        /*
         *  Check that dual-mono does not carry more than 2 tracks, otherwise flag an non-supported error
         */
        if ((pVars->prog_config.front.num_ele > 2) && !(pVars->prog_config.front.ele_is_cpe[tag]))
        {
            status = 1;
        }

        /*
         *  Check that stereo does not carry more than 1 track, otherwise flag an non-supported error
         */
        if ((pVars->prog_config.front.num_ele > 1) && (pVars->prog_config.front.ele_is_cpe[tag]))
        {
            status = 1;
        }



        if (!status)
        {

            /* enter configuration into MC_Info structure */
            status = set_mc_info(&pVars->mc_info,
                                 (tMP4AudioObjectType)(pVars->prog_config.profile + 1),
                                 pVars->prog_config.sampling_rate_idx,
                                 pVars->prog_config.front.ele_tag[tag],
                                 pVars->prog_config.front.ele_is_cpe[tag],
                                 pVars->winmap,
                                 pVars->SFBWidth128);

            if (pVars->mc_info.upsamplingFactor == 2)
            {
                /*
                 *  prog_config.sampling_rate_idx corresponds to the aac base layer,
                 *  if the upsampling factor is active, then the output frequency needs
                 *  to be adjusted accordingly
                 */
                pVars->prog_config.sampling_rate_idx -= 3;
            }

        }


    } /* end if (tag == pVars->current_program) */



    return (status);
}
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
Int huffdecode(
    Int           id_syn_ele,
    BITS          *pInputStream,
    tDec_Int_File *pVars,
    tDec_Int_Chan *pChVars[])

{
    /*----------------------------------------------------------------------------
    ; Define all local variables
    ----------------------------------------------------------------------------*/
    Int      ch;
    Int      common_window;
    Int      hasmask;
    Int      status   = SUCCESS;
    Int      num_channels = 0;
    MC_Info  *pMcInfo;

    per_chan_share_w_fxpCoef *pChLeftShare;  /* Helper pointer */
    per_chan_share_w_fxpCoef *pChRightShare; /* Helper pointer */
    /*----------------------------------------------------------------------------
    ; Function body here
    ----------------------------------------------------------------------------*/

    get9_n_lessbits(
        LEN_TAG,
        pInputStream);

    /* suppose an un-supported id_syn_ele will never be passed */

    common_window = 0;

    if (id_syn_ele == ID_CPE)
    {
        common_window =
            get1bits(pInputStream);
    }

    pMcInfo = &pVars->mc_info;

    /*
     *  check if provided info (num of channels) on audio config,
     *  matches read bitstream data, if not, allow update only once.
     *  In almost all cases it should match.
     */
#if 0     
    if ((pMcInfo->ch_info[0].cpe != id_syn_ele))
    {
        if (pVars->mc_info.implicit_channeling)     /* check done only once */
        {
            pMcInfo->ch_info[0].cpe = id_syn_ele & 1; /*  collect info from bitstream
                                                     *  implicit_channeling flag is locked
                                                     *  after 1st frame, to avoid toggling
                                                     *  parameter in the middle of the clip
                                                     */
            pMcInfo->nch = (id_syn_ele & 1) + 1;     /* update number of channels */
        }
        else
        {
            status = 1; /* ERROR break if syntax error persist  */
        }
    }
#endif

    if (status == SUCCESS)
    {
        if (id_syn_ele == ID_SCE)
        {

            num_channels = 1;
            pVars->hasmask = 0;
        }
        else if (id_syn_ele == ID_CPE)
        {
            pChLeftShare = pChVars[LEFT]->pShareWfxpCoef;
            pChRightShare = pChVars[RIGHT]->pShareWfxpCoef;
            num_channels = 2;

            if (common_window != FALSE)
            {

                status = get_ics_info(
                             (tMP4AudioObjectType) pVars->mc_info.audioObjectType,
                             pInputStream,
                             (Bool)common_window,
                             (WINDOW_SEQUENCE *) & pChVars[LEFT]->wnd,
                             (WINDOW_SHAPE *) & pChVars[LEFT]->wnd_shape_this_bk,
                             pChLeftShare->group,
                             (Int *) & pChLeftShare->max_sfb,
                             pVars->winmap,
                             (LT_PRED_STATUS *) & pChLeftShare->lt_status,
                             (LT_PRED_STATUS *) & pChRightShare->lt_status);

                if (status == SUCCESS)
                {
                    /* copy left channel info to right channel */
                    pChVars[RIGHT]->wnd = pChVars[LEFT]->wnd;
                    pChVars[RIGHT]->wnd_shape_this_bk =
                        pChVars[LEFT]->wnd_shape_this_bk;
                    pChRightShare->max_sfb = pChLeftShare->max_sfb;
                    pv_memcpy(
                        pChRightShare->group,
                        pChLeftShare->group,
                        NSHORT*sizeof(pChLeftShare->group[0]));

                    hasmask = getmask(
                                  pVars->winmap[pChVars[LEFT]->wnd],
                                  pInputStream,
                                  pChLeftShare->group,
                                  pChLeftShare->max_sfb,
                                  pVars->mask);

                    if (hasmask == MASK_ERROR)
                    {
                        status = 1; /* ERROR code */
                    }
                    pVars->hasmask  = hasmask;

                } /* if (status == 0) */
            }
            else
            {
                pVars->hasmask  = 0;
            } /* if (common_window) */

        } /* if (id_syn_ele) */
        else if (id_syn_ele == ID_LFE)
        {
            num_channels = 1;
            pVars->hasmask = 0;
        } /* if (id_syn_ele) == ID_LFE */

    } /* if (status) */

    ch = 0;
    while ((ch < num_channels) && (status == SUCCESS))
    {
        pChLeftShare = pChVars[ch]->pShareWfxpCoef;

        status = getics(
                     pInputStream,
                     common_window,
                     pVars,
                     pChVars[ch],
                     pChLeftShare->group,
                     &pChLeftShare->max_sfb,
                     pChLeftShare->cb_map,
                     &pChLeftShare->tns,
                     pVars->winmap,
                     &pVars->share.a.pulseInfo,
                     pVars->share.a.sect);

        ch++;

    } /* while (ch) */

    /*----------------------------------------------------------------------------
    ; Return status
    ----------------------------------------------------------------------------*/

    return status;

} /* huffdecode */
void pvmp3_reorder(int32 xr[SUBBANDS_NUMBER*FILTERBANK_BANDS],
                   granuleInfo *gr_info,
                   int32  *used_freq_lines,
                   mp3Header *info,
                   int32  Scratch_mem[168])
{
    int32 sfreq =  info->version_x + (info->version_x << 1);
    sfreq += info->sampling_frequency;

    if (gr_info->window_switching_flag && (gr_info->block_type == 2))
    {
        int32   sfb_lines;
        int32   freq;
        int32   src_line;
        int32   sfb;
        if (gr_info->mixed_block_flag)
        {
            /* REORDERING FOR REST SWITCHED SHORT */
            sfb = 3;  /* no reorder for low 2 subbands */
            src_line = 36;
        }
        else
        {  /* pure short */
            sfb = 0;
            src_line = 0;
        }
        int16 ct = src_line;

        for (; sfb < 13; sfb++)
        {
            if (*used_freq_lines > 3*mp3_sfBandIndex[sfreq].s[sfb+1])
            {
                sfb_lines = mp3_sfBandIndex[sfreq].s[sfb+1]  - mp3_sfBandIndex[sfreq].s[sfb];

                for (freq = 0; freq < 3*sfb_lines; freq += 3)
                {
                    int32 tmp1 = xr[src_line];
                    int32 tmp2 = xr[src_line+(sfb_lines)];
                    int32 tmp3 = xr[src_line+(sfb_lines<<1)];
                    src_line++;
                    Scratch_mem[freq  ] = tmp1;
                    Scratch_mem[freq+1] = tmp2;
                    Scratch_mem[freq+2] = tmp3;
                }
                src_line += (sfb_lines << 1);

                pv_memcpy(&xr[ct], Scratch_mem, sfb_lines*3*sizeof(int32));
                ct += sfb_lines + (sfb_lines << 1);

            }
            else
            {

                sfb_lines = mp3_sfBandIndex[sfreq].s[sfb+1]  - mp3_sfBandIndex[sfreq].s[sfb];

                for (freq = 0; freq < 3*sfb_lines; freq += 3)
                {
                    int32 tmp1 = xr[src_line];
                    int32 tmp2 = xr[src_line+(sfb_lines)];
                    int32 tmp3 = xr[src_line+(sfb_lines<<1)];
                    src_line++;
                    Scratch_mem[freq  ] = tmp1;
                    Scratch_mem[freq+1] = tmp2;
                    Scratch_mem[freq+2] = tmp3;
                }

                pv_memcpy(&xr[ct], Scratch_mem, sfb_lines*3*sizeof(int32));

                *used_freq_lines = mp3_sfBandIndex[sfreq].s[sfb+1] * 3;

                sfb = 13;   /* force out of the for-loop */
            }
        }
    }
}
Beispiel #11
0
void low_pass_filt_7k(
    int16 signal[],                      /* input:  signal                  */
    int16 lg,                            /* input:  length of input         */
    int16 mem[],                         /* in/out: memory (size=30)        */
    int16 x[]
)
{
    int16 i, j;
    int32 L_tmp1;
    int32 L_tmp2;
    int32 L_tmp3;
    int32 L_tmp4;

    pv_memcpy((void *)x, (void *)mem, (L_FIR)*sizeof(*x));

    for (i = 0; i < lg >> 2; i++)
    {
        x[(i<<2) + L_FIR    ] = signal[(i<<2)];
        x[(i<<2) + L_FIR + 1] = signal[(i<<2)+1];
        x[(i<<2) + L_FIR + 2] = signal[(i<<2)+2];
        x[(i<<2) + L_FIR + 3] = signal[(i<<2)+3];

        L_tmp1 = fxp_mac_16by16(x[(i<<2)] + signal[(i<<2)], fir_7k[0], 0x00004000);
        L_tmp2 = fxp_mac_16by16(x[(i<<2)+1] + signal[(i<<2)+1], fir_7k[0], 0x00004000);
        L_tmp3 = fxp_mac_16by16(x[(i<<2)+2] + signal[(i<<2)+2], fir_7k[0], 0x00004000);
        L_tmp4 = fxp_mac_16by16(x[(i<<2)+3] + signal[(i<<2)+3], fir_7k[0], 0x00004000);

        for (j = 1; j < L_FIR - 1; j += 4)
        {


            int16 tmp1 = x[(i<<2)+j  ];
            int16 tmp2 = x[(i<<2)+j+1];
            int16 tmp3 = x[(i<<2)+j+2];

            L_tmp1 = fxp_mac_16by16(tmp1, fir_7k[j  ], L_tmp1);
            L_tmp2 = fxp_mac_16by16(tmp2, fir_7k[j  ], L_tmp2);
            L_tmp1 = fxp_mac_16by16(tmp2, fir_7k[j+1], L_tmp1);
            L_tmp2 = fxp_mac_16by16(tmp3, fir_7k[j+1], L_tmp2);
            L_tmp3 = fxp_mac_16by16(tmp3, fir_7k[j  ], L_tmp3);
            L_tmp1 = fxp_mac_16by16(tmp3, fir_7k[j+2], L_tmp1);

            tmp1 = x[(i<<2)+j+3];
            tmp2 = x[(i<<2)+j+4];

            L_tmp2 = fxp_mac_16by16(tmp1, fir_7k[j+2], L_tmp2);
            L_tmp4 = fxp_mac_16by16(tmp1, fir_7k[j  ], L_tmp4);
            L_tmp3 = fxp_mac_16by16(tmp1, fir_7k[j+1], L_tmp3);
            L_tmp1 = fxp_mac_16by16(tmp1, fir_7k[j+3], L_tmp1);
            L_tmp2 = fxp_mac_16by16(tmp2, fir_7k[j+3], L_tmp2);
            L_tmp4 = fxp_mac_16by16(tmp2, fir_7k[j+1], L_tmp4);
            L_tmp3 = fxp_mac_16by16(tmp2, fir_7k[j+2], L_tmp3);

            tmp1 = x[(i<<2)+j+5];
            tmp2 = x[(i<<2)+j+6];

            L_tmp4 = fxp_mac_16by16(tmp1, fir_7k[j+2], L_tmp4);
            L_tmp3 = fxp_mac_16by16(tmp1, fir_7k[j+3], L_tmp3);
            L_tmp4 = fxp_mac_16by16(tmp2, fir_7k[j+3], L_tmp4);

        }

        L_tmp1 = fxp_mac_16by16(x[(i<<2)+j  ], fir_7k[j  ], L_tmp1);
        L_tmp2 = fxp_mac_16by16(x[(i<<2)+j+1], fir_7k[j  ], L_tmp2);
        L_tmp3 = fxp_mac_16by16(x[(i<<2)+j+2], fir_7k[j  ], L_tmp3);
        L_tmp4 = fxp_mac_16by16(x[(i<<2)+j+3], fir_7k[j  ], L_tmp4);

        signal[(i<<2)] = (int16)(L_tmp1 >> 15);
        signal[(i<<2)+1] = (int16)(L_tmp2 >> 15);
        signal[(i<<2)+2] = (int16)(L_tmp3 >> 15);
        signal[(i<<2)+3] = (int16)(L_tmp4 >> 15);

    }

    pv_memcpy((void *)mem, (void *)(x + lg), (L_FIR)*sizeof(*mem));

    return;
}
Beispiel #12
0
void sbr_dec(Int16 *inPcmData,
             Int16 *ftimeOutPtr,
             SBR_FRAME_DATA * hFrameData,
             int32_t applyProcessing,
             SBR_DEC *sbrDec,
#ifdef HQ_SBR
#ifdef PARAMETRICSTEREO
             Int16 * ftimeOutPtrPS,
             HANDLE_PS_DEC hParametricStereoDec,
#endif
#endif
             tDec_Int_File  *pVars)
{
    int32_t   i;
    int32_t   j;
    int32_t   m;

    int32_t  *frameInfo = hFrameData->frameInfo;
    Int  num_qmf_bands;

#ifdef HQ_SBR
#ifdef PARAMETRICSTEREO

    int32_t env;

    int32_t *qmf_PS_generated_Real;
    int32_t *qmf_PS_generated_Imag;

    int32_t *Sr_x;
    int32_t *Si_x;


#endif
#endif

    int32_t(*scratch_mem)[64];
    Int16 *circular_buffer_s;

    int32_t   k;
    int32_t *Sr;
    int32_t *Si;
    int32_t *ptr_tmp1;
    int32_t *ptr_tmp2;
    scratch_mem = pVars->scratch.scratch_mem;


    if (applyProcessing)
    {
        num_qmf_bands = sbrDec->lowSubband;
    }
    else
    {
        num_qmf_bands = 32;     /* becomes a resampler by 2  */
    }

    /* -------------------------------------------------- */
    /*
     *    Re-Load Buffers
     */
    pv_memmove(&hFrameData->sbrQmfBufferReal[0],
               &hFrameData->HistsbrQmfBufferReal[0],
               6*SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferReal));
#ifdef HQ_SBR


    if (sbrDec->LC_aacP_DecoderFlag == OFF)
    {
        pv_memmove(&hFrameData->sbrQmfBufferImag[0],
                   &hFrameData->HistsbrQmfBufferImag[0],
                   6*SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferImag));
    }
#endif
    /* -------------------------------------------------- */


    /*
     *    low band codec signal subband filtering
     */

    for (i = 0; i < 32; i++)
    {

        if (sbrDec->LC_aacP_DecoderFlag == ON)
        {

            calc_sbr_anafilterbank_LC(hFrameData->codecQmfBufferReal[sbrDec->bufWriteOffs + i],
                                      &inPcmData[319] + (i << 5),
                                      scratch_mem,
                                      num_qmf_bands);

        }
#ifdef HQ_SBR
        else
        {

            calc_sbr_anafilterbank(hFrameData->codecQmfBufferReal[sbrDec->bufWriteOffs + i],
                                   hFrameData->codecQmfBufferImag[sbrDec->bufWriteOffs + i],
                                   &inPcmData[319] + (i << 5),
                                   scratch_mem,
                                   num_qmf_bands);
        }
#endif

    }

    if (pVars->ltp_buffer_state)
    {
        pv_memcpy(&inPcmData[-1024-288], &inPcmData[1024], 288*sizeof(*inPcmData));
    }
    else
    {
        pv_memcpy(&inPcmData[1024 + 288], &inPcmData[1024], 288*sizeof(*inPcmData));
    }


    if (applyProcessing)
    {

        /*
         *  Inverse filtering of lowband + HF generation
         */

        if (sbrDec->LC_aacP_DecoderFlag == ON)
        {

            sbr_generate_high_freq((int32_t(*)[32])(hFrameData->codecQmfBufferReal + sbrDec->bufReadOffs),
                                   NULL,
                                   (int32_t *)(hFrameData->sbrQmfBufferReal),
                                   NULL,
                                   hFrameData->sbr_invf_mode,
                                   hFrameData->sbr_invf_mode_prev,
                                   &(sbrDec->FreqBandTableNoise[1]),
                                   sbrDec->NoNoiseBands,
                                   sbrDec->lowSubband,
                                   sbrDec->V_k_master,
                                   sbrDec->Num_Master,
                                   sbrDec->outSampleRate,
                                   frameInfo,
                                   hFrameData->degreeAlias,
                                   scratch_mem,
                                   hFrameData->BwVector,/* */
                                   hFrameData->BwVectorOld,
                                   &(sbrDec->Patch),
                                   sbrDec->LC_aacP_DecoderFlag,
                                   &(sbrDec->highSubband));


            /*
             *      Adjust envelope of current frame.
             */

            calc_sbr_envelope(hFrameData,
                              (int32_t *)(hFrameData->sbrQmfBufferReal),
                              NULL,
                              sbrDec->FreqBandTable,
                              sbrDec->NSfb,
                              sbrDec->FreqBandTableNoise,
                              sbrDec->NoNoiseBands,
                              hFrameData->reset_flag,
                              hFrameData->degreeAlias,
                              &(hFrameData->harm_index),
                              &(hFrameData->phase_index),
                              hFrameData->hFp,
                              &(hFrameData->sUp),
                              sbrDec->limSbc,
                              sbrDec->gateMode,
#ifdef HQ_SBR
                              NULL,
                              NULL,
                              NULL,
                              NULL,
#endif
                              scratch_mem,
                              sbrDec->Patch,
                              sbrDec->sqrt_cache,
                              sbrDec->LC_aacP_DecoderFlag);
        }
#ifdef HQ_SBR
        else
        {

            sbr_generate_high_freq((int32_t(*)[32])(hFrameData->codecQmfBufferReal + sbrDec->bufReadOffs),
                                   (int32_t(*)[32])(hFrameData->codecQmfBufferImag + sbrDec->bufReadOffs),
                                   (int32_t *)(hFrameData->sbrQmfBufferReal),
                                   (int32_t *)(hFrameData->sbrQmfBufferImag),
                                   hFrameData->sbr_invf_mode,
                                   hFrameData->sbr_invf_mode_prev,
                                   &(sbrDec->FreqBandTableNoise[1]),
                                   sbrDec->NoNoiseBands,
                                   sbrDec->lowSubband,
                                   sbrDec->V_k_master,
                                   sbrDec->Num_Master,
                                   sbrDec->outSampleRate,
                                   frameInfo,
                                   NULL,
                                   scratch_mem,
                                   hFrameData->BwVector,
                                   hFrameData->BwVectorOld,
                                   &(sbrDec->Patch),
                                   sbrDec->LC_aacP_DecoderFlag,
                                   &(sbrDec->highSubband));

            /*
             *      Adjust envelope of current frame.
             */

            calc_sbr_envelope(hFrameData,
                              (int32_t *)(hFrameData->sbrQmfBufferReal),
                              (int32_t *)(hFrameData->sbrQmfBufferImag),
                              sbrDec->FreqBandTable,
                              sbrDec->NSfb,
                              sbrDec->FreqBandTableNoise,
                              sbrDec->NoNoiseBands,
                              hFrameData->reset_flag,
                              NULL,
                              &(hFrameData->harm_index),
                              &(hFrameData->phase_index),
                              hFrameData->hFp,
                              &(hFrameData->sUp),
                              sbrDec->limSbc,
                              sbrDec->gateMode,
                              hFrameData->fBuf_man,
                              hFrameData->fBuf_exp,
                              hFrameData->fBufN_man,
                              hFrameData->fBufN_exp,
                              scratch_mem,
                              sbrDec->Patch,
                              sbrDec->sqrt_cache,
                              sbrDec->LC_aacP_DecoderFlag);

        }
#endif


    }
    else   /*  else for applyProcessing */
    {
        /* no sbr, set high band buffers to zero */

        for (i = 0; i < SBR_NUM_COLUMNS; i++)
        {
            pv_memset((void *)&hFrameData->sbrQmfBufferReal[i*SBR_NUM_BANDS],
                      0,
                      SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferReal));

#ifdef HQ_SBR
            pv_memset((void *)&hFrameData->sbrQmfBufferImag[i*SBR_NUM_BANDS],
                      0,
                      SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferImag));

#endif
        }

    }


    /*
     *  Synthesis subband filtering.
     */

#ifdef HQ_SBR

#ifdef PARAMETRICSTEREO


    /*
     * psPresentFlag set implies hParametricStereoDec !=NULL, second condition is
     * is just here to prevent CodeSonar warnings.
     */
    if ((pVars->mc_info.psPresentFlag) && (applyProcessing) &&
            (hParametricStereoDec != NULL))
    {

        /*
         *  qmfBufferReal uses the rigth aac channel ( perChan[1] is not used)
         *  followed by the buffer fxpCoef[2][2048]  which makes a total of
         *  2349 + 2048*2 = 6445
         *  These  2 matrices (qmfBufferReal & qmfBufferImag) are
         *  [2][38][64] == 4864 int32_t
         */


        tDec_Int_Chan *tmpx = &pVars->perChan[1];
        /*
         *  dereferencing type-punned pointer avoid
         *  breaking strict-aliasing rules
         */
        int32_t *tmp = (int32_t *)tmpx;
        hParametricStereoDec->qmfBufferReal = (int32_t(*)[64]) tmp;

        tmp = (int32_t *) & hParametricStereoDec->qmfBufferReal[38][0];
        hParametricStereoDec->qmfBufferImag = (int32_t(*)[64]) tmp;

        for (i = 0; i < 32; i++)
        {
            Int   xoverBand;

            if (i < ((hFrameData->frameInfo[1]) << 1))
            {
                xoverBand = sbrDec->prevLowSubband;
            }
            else
            {
                xoverBand = sbrDec->lowSubband;
            }

            if (xoverBand > sbrDec->highSubband)
            {
                xoverBand = 32; /* error condition, default to upsampling mode */
            }

            m = sbrDec->bufReadOffs + i;    /*  2 + i */

            Sr_x = hParametricStereoDec->qmfBufferReal[i];
            Si_x = hParametricStereoDec->qmfBufferImag[i];



            for (int32_t j = 0; j < xoverBand; j++)
            {
                Sr_x[j] = shft_lft_1(hFrameData->codecQmfBufferReal[m][j]);
                Si_x[j] = shft_lft_1(hFrameData->codecQmfBufferImag[m][j]);
            }




            pv_memcpy(&Sr_x[xoverBand],
                      &hFrameData->sbrQmfBufferReal[i*SBR_NUM_BANDS],
                      (sbrDec->highSubband - xoverBand)*sizeof(*Sr_x));

            pv_memcpy(&Si_x[xoverBand],
                      &hFrameData->sbrQmfBufferImag[i*SBR_NUM_BANDS],
                      (sbrDec->highSubband - xoverBand)*sizeof(*Si_x));

            pv_memset((void *)&Sr_x[sbrDec->highSubband],
                      0,
                      (64 - sbrDec->highSubband)*sizeof(*Sr_x));

            pv_memset((void *)&Si_x[sbrDec->highSubband],
                      0,
                      (64 - sbrDec->highSubband)*sizeof(*Si_x));


        }

        for (i = 32; i < 32 + 6; i++)
        {
            m = sbrDec->bufReadOffs + i;     /*  2 + i */

            for (int32_t j = 0; j < 5; j++)
            {
                hParametricStereoDec->qmfBufferReal[i][j] = shft_lft_1(hFrameData->codecQmfBufferReal[m][j]);
                hParametricStereoDec->qmfBufferImag[i][j] = shft_lft_1(hFrameData->codecQmfBufferImag[m][j]);
            }

        }


        /*
         *    Update Buffers
         */
        for (i = 0; i < sbrDec->bufWriteOffs; i++)     /* sbrDec->bufWriteOffs set to 8 and unchanged */
        {
            j = sbrDec->noCols + i;                    /* sbrDec->noCols set to 32 and unchanged */

            pv_memmove(hFrameData->codecQmfBufferReal[i],         /* to    */
                       hFrameData->codecQmfBufferReal[j],        /* from  */
                       sizeof(*hFrameData->codecQmfBufferReal[i]) << 5);

            pv_memmove(hFrameData->codecQmfBufferImag[i],
                       hFrameData->codecQmfBufferImag[j],
                       sizeof(*hFrameData->codecQmfBufferImag[i]) << 5);
        }


        pv_memmove(&hFrameData->HistsbrQmfBufferReal[0],
                   &hFrameData->sbrQmfBufferReal[32*SBR_NUM_BANDS],
                   6*SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferReal));

        pv_memmove(&hFrameData->HistsbrQmfBufferImag[0],
                   &hFrameData->sbrQmfBufferImag[32*SBR_NUM_BANDS],
                   6*SBR_NUM_BANDS*sizeof(*hFrameData->sbrQmfBufferImag));


        /*
         *   Needs whole QMF matrix formed before applying
         *   Parametric stereo processing.
         */

        qmf_PS_generated_Real = scratch_mem[0];
        qmf_PS_generated_Imag = scratch_mem[1];
        env = 0;

        /*
         *  Set circular buffer for Left channel
         */

        circular_buffer_s = (Int16 *)scratch_mem[7];


        if (pVars->mc_info.bDownSampledSbr)
        {
            pv_memmove(&circular_buffer_s[2048],
                       hFrameData->V,
                       640*sizeof(*circular_buffer_s));
        }
        else
        {
            pv_memmove(&circular_buffer_s[4096],
                       hFrameData->V,
                       1152*sizeof(*circular_buffer_s));

        }


        /*
         *  Set Circular buffer for PS hybrid analysis
         */
        for (i = 0, j = 0; i < 3; i++)
        {

            pv_memmove(&scratch_mem[2][32 + j     ],
                       hParametricStereoDec->hHybrid->mQmfBufferReal[i],
                       HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal));
            pv_memmove(&scratch_mem[2][32 + j + 44],
                       hParametricStereoDec->hHybrid->mQmfBufferImag[i],
                       HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag));
            j += 88;
        }

        pv_memset((void *)&qmf_PS_generated_Real[hParametricStereoDec->usb],
                  0,
                  (64 - hParametricStereoDec->usb)*sizeof(*qmf_PS_generated_Real));

        pv_memset((void *)&qmf_PS_generated_Imag[hParametricStereoDec->usb],
                  0,
                  (64 - hParametricStereoDec->usb)*sizeof(*qmf_PS_generated_Imag));


        for (i = 0; i < 32; i++)
        {
            if (i == (Int)hParametricStereoDec-> aEnvStartStop[env])
            {
                ps_init_stereo_mixing(hParametricStereoDec, env, sbrDec->highSubband);
                env++;
            }


            ps_applied(hParametricStereoDec,
                       &hParametricStereoDec->qmfBufferReal[i],
                       &hParametricStereoDec->qmfBufferImag[i],
                       qmf_PS_generated_Real,
                       qmf_PS_generated_Imag,
                       scratch_mem[2],
                       i);

            /* Create time samples for regular mono channel */

            if (pVars->mc_info.bDownSampledSbr)
            {
                calc_sbr_synfilterbank(hParametricStereoDec->qmfBufferReal[i],  /* realSamples  */
                                       hParametricStereoDec->qmfBufferImag[i], /* imagSamples  */
                                       ftimeOutPtr + (i << 6),
                                       &circular_buffer_s[1984 - (i<<6)],
                                       pVars->mc_info.bDownSampledSbr);
            }
            else
            {
                calc_sbr_synfilterbank(hParametricStereoDec->qmfBufferReal[i],  /* realSamples  */
                                       hParametricStereoDec->qmfBufferImag[i], /* imagSamples  */
                                       ftimeOutPtr + (i << 7),
                                       &circular_buffer_s[3968 - (i<<7)],
                                       pVars->mc_info.bDownSampledSbr);

            }

            pv_memmove(hParametricStereoDec->qmfBufferReal[i], qmf_PS_generated_Real, 64*sizeof(*qmf_PS_generated_Real));
            pv_memmove(hParametricStereoDec->qmfBufferImag[i], qmf_PS_generated_Imag, 64*sizeof(*qmf_PS_generated_Real));

        }


        /*
         *  Save Circular buffer history used on PS hybrid analysis
         */

        for (i = 0, j = 0; i < 3; i++)
        {
            pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferReal[i],
                       &scratch_mem[2][ 64 + j     ],
                       HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferReal));

            pv_memmove(hParametricStereoDec->hHybrid->mQmfBufferImag[i],
                       &scratch_mem[2][ 64 + j + 44],
                       HYBRID_FILTER_LENGTH_m_1*sizeof(*hParametricStereoDec->hHybrid->mQmfBufferImag));

            j += 88;
        }

        pv_memmove(hFrameData->V, &circular_buffer_s[0], 1152*sizeof(*circular_buffer_s));

        /*
         *  Set circular buffer for Right channel
         */

        circular_buffer_s = (Int16 *)scratch_mem[5];

        if (pVars->mc_info.bDownSampledSbr)
        {
            pv_memmove(&circular_buffer_s[2048],
                       (int32_t *)hParametricStereoDec->R_ch_qmf_filter_history,
                       640*sizeof(*circular_buffer_s));
        }
        else
        {
            pv_memmove(&circular_buffer_s[4096],
                       (int32_t *)hParametricStereoDec->R_ch_qmf_filter_history,
                       1152*sizeof(*circular_buffer_s));

        }


        for (i = 0; i < 32; i++)
        {
            if (pVars->mc_info.bDownSampledSbr)
            {

                calc_sbr_synfilterbank(hParametricStereoDec->qmfBufferReal[i],  /* realSamples  */
                                       hParametricStereoDec->qmfBufferImag[i], /* imagSamples  */
                                       ftimeOutPtrPS + (i << 6),
                                       &circular_buffer_s[1984 - (i<<6)],
                                       pVars->mc_info.bDownSampledSbr);
            }
            else
            {
                calc_sbr_synfilterbank(hParametricStereoDec->qmfBufferReal[i],  /* realSamples  */
                                       hParametricStereoDec->qmfBufferImag[i], /* imagSamples  */
                                       ftimeOutPtrPS + (i << 7),
                                       &circular_buffer_s[3968 - (i<<7)],
                                       pVars->mc_info.bDownSampledSbr);
            }

        }

        if (pVars->mc_info.bDownSampledSbr)
        {
            pv_memmove((int32_t *)hParametricStereoDec->R_ch_qmf_filter_history, &circular_buffer_s[0], 640*sizeof(*circular_buffer_s));
        }
        else
        {
            pv_memmove((int32_t *)hParametricStereoDec->R_ch_qmf_filter_history, &circular_buffer_s[0], 1152*sizeof(*circular_buffer_s));
        }





    }
    else    /*  else -- sbrEnablePS  */
    {

#endif      /*   PARAMETRICSTEREO */
#endif      /*   HQ_SBR */

        /*
         *  Use shared aac memory as continuous buffer
         */


        Sr  = scratch_mem[0];
        Si  = scratch_mem[1];

        circular_buffer_s = (Int16*)scratch_mem[2];

        if (pVars->mc_info.bDownSampledSbr)
        {

            pv_memmove(&circular_buffer_s[2048],
                       hFrameData->V,
                       640*sizeof(*circular_buffer_s));
        }
        else
        {
            pv_memmove(&circular_buffer_s[4096],
                       hFrameData->V,
                       1152*sizeof(*circular_buffer_s));
        }

        for (i = 0; i < 32; i++)
        {
            Int   xoverBand;

            if (applyProcessing)
            {
                if (i < ((hFrameData->frameInfo[1]) << 1))
                {
                    xoverBand = sbrDec->prevLowSubband;

                }
                else
                {
                    xoverBand = sbrDec->lowSubband;
                }

                if (xoverBand > sbrDec->highSubband)
                {
                    xoverBand = 32; /* error condition, default to upsampling mode */
                }
            }
            else
            {
                xoverBand = 32;
                sbrDec->highSubband = 32;
            }


            m = sbrDec->bufReadOffs + i;    /* sbrDec->bufReadOffs == 2 */


            ptr_tmp1 = (hFrameData->codecQmfBufferReal[m]);
            ptr_tmp2 = Sr;

            if (sbrDec->LC_aacP_DecoderFlag == ON)
            {

                for (k = (xoverBand >> 1); k != 0; k--)
                {
                    *(ptr_tmp2++) = (*(ptr_tmp1++)) >> 9;
                    *(ptr_tmp2++) = (*(ptr_tmp1++)) >> 9;
                }
                if (xoverBand & 1)
                {
                    *(ptr_tmp2++) = (*(ptr_tmp1)) >> 9;
                }

                ptr_tmp1 = &hFrameData->sbrQmfBufferReal[i*SBR_NUM_BANDS];


                for (k = xoverBand; k < sbrDec->highSubband; k++)
                {
                    *(ptr_tmp2++) = (*(ptr_tmp1++)) << 1;
                }

                pv_memset((void *)ptr_tmp2,
                          0,
                          (64 - sbrDec->highSubband)*sizeof(*ptr_tmp2));


                if (pVars->mc_info.bDownSampledSbr)
                {
                    calc_sbr_synfilterbank_LC(Sr,               /* realSamples  */
                                              ftimeOutPtr + (i << 6),
                                              &circular_buffer_s[1984 - (i<<6)],
                                              pVars->mc_info.bDownSampledSbr);
                }
                else
                {
                    calc_sbr_synfilterbank_LC(Sr,               /* realSamples  */
                                              ftimeOutPtr + (i << 7),
                                              &circular_buffer_s[3968 - (i<<7)],
                                              pVars->mc_info.bDownSampledSbr);
                }
            }
#ifdef HQ_SBR
            else
            {

                for (k = xoverBand; k != 0; k--)
                {
                    *(ptr_tmp2++) = shft_lft_1(*(ptr_tmp1++));
                }

                ptr_tmp1 = &hFrameData->sbrQmfBufferReal[i*SBR_NUM_BANDS];
                ptr_tmp2 = &Sr[xoverBand];


                for (k = xoverBand; k < sbrDec->highSubband; k++)
                {
                    *(ptr_tmp2++) = (*(ptr_tmp1++));
                }

                pv_memset((void *)ptr_tmp2,
                          0,
                          (64 - sbrDec->highSubband)*sizeof(*ptr_tmp2));


                ptr_tmp1 = (hFrameData->codecQmfBufferImag[m]);
                ptr_tmp2 = Si;

                for (k = (xoverBand >> 1); k != 0; k--)
                {
                    *(ptr_tmp2++) = shft_lft_1(*(ptr_tmp1++));
                    *(ptr_tmp2++) = shft_lft_1(*(ptr_tmp1++));
                }
                if (xoverBand & 1)
                {
                    *(ptr_tmp2) = shft_lft_1(*(ptr_tmp1));
                }

                ptr_tmp1 = &hFrameData->sbrQmfBufferImag[i*SBR_NUM_BANDS];
                ptr_tmp2 = &Si[xoverBand];

                for (k = xoverBand; k < sbrDec->highSubband; k++)
                {
                    *(ptr_tmp2++) = (*(ptr_tmp1++));
                }

                pv_memset((void *)ptr_tmp2,
                          0,
                          (64 - sbrDec->highSubband)*sizeof(*ptr_tmp2));


                if (pVars->mc_info.bDownSampledSbr)
                {
                    calc_sbr_synfilterbank(Sr,              /* realSamples  */
                                           Si,             /* imagSamples  */
                                           ftimeOutPtr + (i << 6),
                                           &circular_buffer_s[1984 - (i<<6)],
                                           pVars->mc_info.bDownSampledSbr);
                }
                else
                {
                    calc_sbr_synfilterbank(Sr,              /* realSamples  */
                                           Si,             /* imagSamples  */
                                           ftimeOutPtr + (i << 7),
                                           &circular_buffer_s[3968 - (i<<7)],
                                           pVars->mc_info.bDownSampledSbr);
                }
            }
#endif

        }
/*----------------------------------------------------------------------------
; FUNCTION CODE
----------------------------------------------------------------------------*/
void deinterleave(
    Int16        interleaved[],
    Int16        deinterleaved[],
    FrameInfo   *pFrameInfo)
{

    Int      group;  /* group index */
    Int      sfb;    /* scalefactor band index */
    Int      win;    /* window index */
    Int16    *pGroup;
    Int16    *pWin;
    Int16    *pStart;
    Int16    *pInterleaved;
    Int16    *pDeinterleaved;
    Int      sfb_inc;

    Int      ngroups;
    Int     *pGroupLen;
    Int     *pSfbPerWin;
    Int     *pSfbWidth;

    pInterleaved   = interleaved;
    pDeinterleaved = deinterleaved;

    pSfbPerWin  = pFrameInfo->sfb_per_win;
    ngroups     = pFrameInfo->num_groups;
    pGroupLen   = pFrameInfo->group_len;

    pGroup = pDeinterleaved;

    for (group = ngroups; group > 0; group--)
    {
        pSfbWidth   = pFrameInfo->sfb_width_128;
        sfb_inc = 0;
        pStart = pInterleaved;

        /* Perform the deinterleaving across all windows in a group */

        for (sfb = pSfbPerWin[ngroups-group]; sfb > 0; sfb--)
        {
            pWin = pGroup;

            for (win = pGroupLen[ngroups-group]; win > 0; win--)
            {
                pDeinterleaved = pWin + sfb_inc;

                pv_memcpy(
                    pDeinterleaved,
                    pInterleaved,
                    *pSfbWidth*sizeof(*pInterleaved));

                pInterleaved += *pSfbWidth;

                pWin += SN2;

            } /* for (win) */

            sfb_inc += *pSfbWidth++;

        } /* for (sfb) */

        pGroup += (pInterleaved - pStart);

    } /* for (group) */

} /* deinterleave */