예제 #1
0
static void auto_correlation(sbr_info *sbr, acorr_coef *ac, qmf_t buffer[MAX_NTSRHFG][64],
                             uint8_t bd, uint8_t len)
{
    real_t r01r = 0, r01i = 0, r02r = 0, r02i = 0, r11r = 0;
    real_t temp1_r, temp1_i, temp2_r, temp2_i, temp3_r, temp3_i;
    real_t temp4_r, temp4_i, temp5_r, temp5_i;
    int8_t j;
    uint8_t offset = sbr->tHFAdj;
    const real_t rel = FRAC_CONST(0.999999); // 1 / (1 + 1e-6f);

    temp2_r = ACDET_PRE(QMF_RE(buffer[offset-2][bd]));
    temp2_i = ACDET_PRE(QMF_IM(buffer[offset-2][bd]));
    temp3_r = ACDET_PRE(QMF_RE(buffer[offset-1][bd]));
    temp3_i = ACDET_PRE(QMF_IM(buffer[offset-1][bd]));
    // Save these because they are needed after loop
    temp4_r = temp2_r;
    temp4_i = temp2_i;
    temp5_r = temp3_r;
    temp5_i = temp3_i;

    for (j = offset; j < len + offset; j++)
    {
        temp1_r = temp2_r;
        temp1_i = temp2_i;
        temp2_r = temp3_r;
        temp2_i = temp3_i;
        temp3_r = ACDET_PRE(QMF_RE(buffer[j][bd]));
        temp3_i = ACDET_PRE(QMF_IM(buffer[j][bd]));
        r01r += MUL_F(temp3_r, temp2_r) + MUL_F(temp3_i, temp2_i);
        r01i += MUL_F(temp3_i, temp2_r) - MUL_F(temp3_r, temp2_i);
        r02r += MUL_F(temp3_r, temp1_r) + MUL_F(temp3_i, temp1_i);
        r02i += MUL_F(temp3_i, temp1_r) - MUL_F(temp3_r, temp1_i);
        r11r += MUL_F(temp2_r, temp2_r) + MUL_F(temp2_i, temp2_i);
    }

    RE(ac->r12) = r01r - (MUL_F(temp3_r, temp2_r) + MUL_F(temp3_i, temp2_i)) +
                         (MUL_F(temp5_r, temp4_r) + MUL_F(temp5_i, temp4_i));
    IM(ac->r12) = r01i - (MUL_F(temp3_i, temp2_r) - MUL_F(temp3_r, temp2_i)) +
                         (MUL_F(temp5_i, temp4_r) - MUL_F(temp5_r, temp4_i));
    RE(ac->r22) = r11r - (MUL_F(temp2_r, temp2_r) + MUL_F(temp2_i, temp2_i)) +
                         (MUL_F(temp4_r, temp4_r) + MUL_F(temp4_i, temp4_i));
    RE(ac->r01) = r01r;
    IM(ac->r01) = r01i;
    RE(ac->r02) = r02r;
    IM(ac->r02) = r02i;
    RE(ac->r11) = r11r;

    ac->det = MUL_F(RE(ac->r11), RE(ac->r22)) - MUL_F((MUL_F(RE(ac->r12), RE(ac->r12)) + MUL_F(IM(ac->r12), IM(ac->r12))), rel);
    ac->det = ACDET_POST(ac->det);

}
예제 #2
0
static void auto_correlation(sbr_info *sbr, acorr_coef *ac,
                             qmf_t buffer[MAX_NTSRHFG][64],
                             uint8_t bd, uint8_t len)
{
    real_t r01 = 0, r02 = 0, r11 = 0;
    real_t tmp1, tmp2;
    int8_t j;
    uint8_t offset = sbr->tHFAdj;
    const real_t rel = FRAC_CONST(0.999999); // 1 / (1 + 1e-6f);

    for (j = offset; j < len + offset; j++)
    {
        real_t buf_j   = ACDET_PRE(QMF_RE(buffer[j  ][bd]));
        real_t buf_j_1 = ACDET_PRE(QMF_RE(buffer[j-1][bd]));
        real_t buf_j_2 = ACDET_PRE(QMF_RE(buffer[j-2][bd]));

        r01 += MUL_F(buf_j  , buf_j_1);
        r02 += MUL_F(buf_j  , buf_j_2);
        r11 += MUL_F(buf_j_1, buf_j_1);
    }
    tmp1 = ACDET_PRE(QMF_RE(buffer[len+offset-1][bd]));
    tmp2 = ACDET_PRE(QMF_RE(buffer[    offset-1][bd]));
    RE(ac->r12) = r01 - MUL_F(tmp1, tmp1) + MUL_F(tmp2, tmp2);

    tmp1 = ACDET_PRE(QMF_RE(buffer[len+offset-2][bd]));
    tmp2 = ACDET_PRE(QMF_RE(buffer[    offset-2][bd]));
    RE(ac->r22) = r11 - MUL_F(tmp1, tmp1) + MUL_F(tmp2, tmp2);
    RE(ac->r01) = r01;
    RE(ac->r02) = r02;
    RE(ac->r11) = r11;

    ac->det = MUL_F(RE(ac->r11), RE(ac->r22)) - MUL_F(MUL_F(RE(ac->r12), RE(ac->r12)), rel);
    ac->det = ACDET_POST(ac->det);
}
예제 #3
0
static void ps_dummy_function(qmf_t X_mono[MAX_NTSR][64],
                              qmf_t X_left[MAX_NTSR][64], qmf_t X_right[MAX_NTSR][64])
{
    uint8_t i, j;

    for (i = 0; i < MAX_NTSR; i++)
    {
        for (j = 0; j < 64; j++)
        {
            QMF_RE(X_left[i][j]) = QMF_RE(X_mono[i][j]);
            QMF_RE(X_right[i][j]) = QMF_RE(X_mono[i][j]);
#ifndef SBR_LOW_POWER
            QMF_IM(X_left[i][j]) = QMF_IM(X_mono[i][j]);
            QMF_IM(X_right[i][j]) = QMF_IM(X_mono[i][j]);
#endif
        }
    }
}
예제 #4
0
static void sbr_process_channel(sbr_info *sbr, real_t *channel_buf, qmf_t X[MAX_NTSR][64],
                                uint8_t ch, uint8_t dont_process)
{
    int16_t i, k, l;

#ifdef SBR_LOW_POWER
    ALIGN real_t deg[64];
#endif

    if (sbr->frame == 0)
    {
        uint8_t j;
        sbr->qmfa[ch] = qmfa_init(32);
        sbr->qmfs[ch] = qmfs_init(64);

        for (j = 0; j < 5; j++)
        {
            sbr->G_temp_prev[ch][j] = faad_malloc(64*sizeof(real_t));
            sbr->Q_temp_prev[ch][j] = faad_malloc(64*sizeof(real_t));
        }

        memset(sbr->Xsbr[ch], 0, (sbr->numTimeSlotsRate+sbr->tHFGen)*64 * sizeof(qmf_t));
        memset(sbr->Xcodec[ch], 0, (sbr->numTimeSlotsRate+sbr->tHFGen)*32 * sizeof(qmf_t));
    }

    /* subband analysis */
    if (dont_process)
        sbr_qmf_analysis_32(sbr, sbr->qmfa[ch], channel_buf, sbr->Xcodec[ch], sbr->tHFGen, 32);
    else
        sbr_qmf_analysis_32(sbr, sbr->qmfa[ch], channel_buf, sbr->Xcodec[ch], sbr->tHFGen, sbr->kx);

    if (!dont_process)
    {
#if 1
        /* insert high frequencies here */
        /* hf generation using patching */
        hf_generation(sbr, sbr->Xcodec[ch], sbr->Xsbr[ch]
#ifdef SBR_LOW_POWER
            ,deg
#endif
            ,ch);
#endif

#ifdef SBR_LOW_POWER
        for (l = sbr->t_E[ch][0]; l < sbr->t_E[ch][sbr->L_E[ch]]; l++)
        {
            for (k = 0; k < sbr->kx; k++)
            {
                QMF_RE(sbr->Xsbr[ch][sbr->tHFAdj + l][k]) = 0;
            }
        }
#endif

#if 1
        /* hf adjustment */
        hf_adjustment(sbr, sbr->Xsbr[ch]
#ifdef SBR_LOW_POWER
            ,deg
#endif
            ,ch);
#endif
    }

    if ((sbr->just_seeked != 0) || dont_process)
    {
        for (l = 0; l < sbr->numTimeSlotsRate; l++)
        {
            for (k = 0; k < 32; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xcodec[ch][l + sbr->tHFAdj][k]);
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xcodec[ch][l + sbr->tHFAdj][k]);
#endif
            }
            for (k = 32; k < 64; k++)
            {
                QMF_RE(X[l][k]) = 0;
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = 0;
#endif
            }
        }
    } else {
        for (l = 0; l < sbr->numTimeSlotsRate; l++)
        {
            uint8_t xover_band;

            if (l < sbr->t_E[ch][0])
                xover_band = sbr->kx_prev;
            else
                xover_band = sbr->kx;

            for (k = 0; k < xover_band; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xcodec[ch][l + sbr->tHFAdj][k]);
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xcodec[ch][l + sbr->tHFAdj][k]);
#endif
            }
            for (k = xover_band; k < 64; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
#endif
            }
#ifdef SBR_LOW_POWER
            QMF_RE(X[l][xover_band - 1]) += QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][xover_band - 1]);
#endif
        }
    }

    for (i = 0; i < sbr->tHFGen; i++)
    {
        memmove(sbr->Xcodec[ch][i], sbr->Xcodec[ch][i+sbr->numTimeSlotsRate], 32 * sizeof(qmf_t));
        memmove(sbr->Xsbr[ch][i], sbr->Xsbr[ch][i+sbr->numTimeSlotsRate], 64 * sizeof(qmf_t));
    }
}
예제 #5
0
void hf_generation(sbr_info *sbr, qmf_t Xlow[MAX_NTSRHFG][64],
                   qmf_t Xhigh[MAX_NTSRHFG][64]
#ifdef SBR_LOW_POWER
                   ,real_t *deg
#endif
                   ,uint8_t ch)
{
    uint8_t l, i, x;
    ALIGN complex_t alpha_0[64], alpha_1[64];
#ifdef SBR_LOW_POWER
    ALIGN real_t rxx[64];
#endif

    uint8_t offset = sbr->tHFAdj;
    uint8_t first = sbr->t_E[ch][0];
    uint8_t last = sbr->t_E[ch][sbr->L_E[ch]];

    calc_chirp_factors(sbr, ch);

#ifdef SBR_LOW_POWER
    memset(deg, 0, 64*sizeof(real_t));
#endif

    if ((ch == 0) && (sbr->Reset))
        patch_construction(sbr);

    /* calculate the prediction coefficients */
#ifdef SBR_LOW_POWER
    calc_prediction_coef_lp(sbr, Xlow, alpha_0, alpha_1, rxx);
    calc_aliasing_degree(sbr, rxx, deg);
#endif

    /* actual HF generation */
    for (i = 0; i < sbr->noPatches; i++)
    {
        for (x = 0; x < sbr->patchNoSubbands[i]; x++)
        {
            real_t a0_r, a0_i, a1_r, a1_i;
            real_t bw, bw2;
            uint8_t q, p, k, g;

            /* find the low and high band for patching */
            k = sbr->kx + x;
            for (q = 0; q < i; q++)
            {
                k += sbr->patchNoSubbands[q];
            }
            p = sbr->patchStartSubband[i] + x;

#ifdef SBR_LOW_POWER
            if (x != 0 /*x < sbr->patchNoSubbands[i]-1*/)
                deg[k] = deg[p];
            else
                deg[k] = 0;
#endif

            g = sbr->table_map_k_to_g[k];

            bw = sbr->bwArray[ch][g];
            bw2 = MUL_C(bw, bw);

            /* do the patching */
            /* with or without filtering */
            if (bw2 > 0)
            {
                real_t temp1_r, temp2_r, temp3_r;
#ifndef SBR_LOW_POWER
                real_t temp1_i, temp2_i, temp3_i;
                calc_prediction_coef(sbr, Xlow, alpha_0, alpha_1, p);
#endif

                a0_r = MUL_C(RE(alpha_0[p]), bw);
                a1_r = MUL_C(RE(alpha_1[p]), bw2);
#ifndef SBR_LOW_POWER
                a0_i = MUL_C(IM(alpha_0[p]), bw);
                a1_i = MUL_C(IM(alpha_1[p]), bw2);
#endif

                temp2_r = QMF_RE(Xlow[first - 2 + offset][p]);
                temp3_r = QMF_RE(Xlow[first - 1 + offset][p]);
#ifndef SBR_LOW_POWER
                temp2_i = QMF_IM(Xlow[first - 2 + offset][p]);
                temp3_i = QMF_IM(Xlow[first - 1 + offset][p]);
#endif
                for (l = first; l < last; l++)
                {
                    temp1_r = temp2_r;
                    temp2_r = temp3_r;
                    temp3_r = QMF_RE(Xlow[l + offset][p]);
#ifndef SBR_LOW_POWER
                    temp1_i = temp2_i;
                    temp2_i = temp3_i;
                    temp3_i = QMF_IM(Xlow[l + offset][p]);
#endif

#ifdef SBR_LOW_POWER
                    QMF_RE(Xhigh[l + offset][k]) = temp3_r +
                                (MUL_R(a0_r, temp2_r) + MUL_R(a1_r, temp1_r));
#else
                    QMF_RE(Xhigh[l + offset][k]) = temp3_r +
                                (MUL_R(a0_r, temp2_r) - MUL_R(a0_i, temp2_i) +
                                 MUL_R(a1_r, temp1_r) - MUL_R(a1_i, temp1_i));
                    QMF_IM(Xhigh[l + offset][k]) = temp3_i +
                                (MUL_R(a0_i, temp2_r) + MUL_R(a0_r, temp2_i) +
                                 MUL_R(a1_i, temp1_r) + MUL_R(a1_r, temp1_i));
#endif
                }
            } else {
                for (l = first; l < last; l++)
                {
                    QMF_RE(Xhigh[l + offset][k]) = QMF_RE(Xlow[l + offset][p]);
#ifndef SBR_LOW_POWER
                    QMF_IM(Xhigh[l + offset][k]) = QMF_IM(Xlow[l + offset][p]);
#endif
                }
            }
        }
    }

    if (sbr->Reset)
    {
        limiter_frequency_table(sbr);
    }
}
예제 #6
0
static void sbr_process_channel(sbr_info *sbr, real_t *channel_buf, qmf_t X[MAX_NTSR][64],
                                uint8_t ch, uint8_t dont_process,
                                const uint8_t downSampledSBR)
{
    int16_t k, l;

    (void)downSampledSBR;
#ifdef DRM
    if (sbr->Is_DRM_SBR)
    {
        sbr->bsco = max((int32_t)sbr->maxAACLine*32/(int32_t)sbr->frame_len - (int32_t)sbr->kx, 0);
    } else {
#endif
        sbr->bsco = 0;
#ifdef DRM
    }
#endif


//#define PRE_QMF_PRINT
#ifdef PRE_QMF_PRINT
    {
        int i;
        for (i = 0; i < 1024; i++)
        {
            printf("%d\n", channel_buf[i]);
        }
    }
#endif


    /* subband analysis */
    if (dont_process)
        sbr_qmf_analysis_32(sbr, &sbr->qmfa[ch], channel_buf, sbr->Xsbr[ch], sbr->tHFGen, 32);
    else
        sbr_qmf_analysis_32(sbr, &sbr->qmfa[ch], channel_buf, sbr->Xsbr[ch], sbr->tHFGen, sbr->kx);

    if (!dont_process)
    {
#if 1
        /* insert high frequencies here */
        /* hf generation using patching */
        hf_generation(sbr, sbr->Xsbr[ch], sbr->Xsbr[ch]
#ifdef SBR_LOW_POWER
            ,deg
#endif
            ,ch);
#endif

#ifdef SBR_LOW_POWER
        for (l = sbr->t_E[ch][0]; l < sbr->t_E[ch][sbr->L_E[ch]]; l++)
        {
            for (k = 0; k < sbr->kx; k++)
            {
                QMF_RE(sbr->Xsbr[ch][sbr->tHFAdj + l][k]) = 0;
            }
        }
#endif

#if 1
        /* hf adjustment */
        hf_adjustment(sbr, sbr->Xsbr[ch]
#ifdef SBR_LOW_POWER
            ,deg
#endif
            ,ch);
#endif
    }

    if ((sbr->just_seeked != 0) || dont_process)
    {
        for (l = 0; l < sbr->numTimeSlotsRate; l++)
        {
            for (k = 0; k < 32; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
#endif
            }
            for (k = 32; k < 64; k++)
            {
                QMF_RE(X[l][k]) = 0;
#ifndef SBR_LOW_POWER
                QMF_IM(X[l][k]) = 0;
#endif
            }
        }
    } else {
        for (l = 0; l < sbr->numTimeSlotsRate; l++)
        {
            uint8_t kx_band, M_band, bsco_band;

            if (l < sbr->t_E[ch][0])
            {
                kx_band = sbr->kx_prev;
                M_band = sbr->M_prev;
                bsco_band = sbr->bsco_prev;
            } else {
                kx_band = sbr->kx;
                M_band = sbr->M;
                bsco_band = sbr->bsco;
            }

#ifndef SBR_LOW_POWER
            for (k = 0; k < kx_band + bsco_band; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
            }
            for (k = kx_band + bsco_band; k < kx_band + M_band; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
                QMF_IM(X[l][k]) = QMF_IM(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
            }
            for (k = max(kx_band + bsco_band, kx_band + M_band); k < 64; k++)
            {
                QMF_RE(X[l][k]) = 0;
                QMF_IM(X[l][k]) = 0;
            }
#else
            for (k = 0; k < kx_band + bsco_band; k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
            }
            for (k = kx_band + bsco_band; k < min(kx_band + M_band, 63); k++)
            {
                QMF_RE(X[l][k]) = QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][k]);
            }
            for (k = max(kx_band + bsco_band, kx_band + M_band); k < 64; k++)
            {
                QMF_RE(X[l][k]) = 0;
            }
            QMF_RE(X[l][kx_band - 1 + bsco_band]) +=
                QMF_RE(sbr->Xsbr[ch][l + sbr->tHFAdj][kx_band - 1 + bsco_band]);
#endif
        }
    }
}
예제 #7
0
uint8_t sbrDecodeSingleFramePS(sbr_info *sbr, real_t *left_channel, real_t *right_channel,
                               const uint8_t just_seeked, const uint8_t downSampledSBR)
{
    uint8_t l, k;
    uint8_t dont_process = 0;
    uint8_t ret = 0;

    memset(p_XLR->X_L, 0, sizeof(*p_XLR->X_L));
    memset(p_XLR->X_R, 0, sizeof(*p_XLR->X_R));
    if (sbr == NULL)
        return 20;

    /* case can occur due to bit errors */
    if (sbr->id_aac != ID_SCE && sbr->id_aac != ID_LFE)
        return 21;

    if (sbr->ret || (sbr->header_count == 0))
    {
        /* don't process just upsample */
        dont_process = 1;

        /* Re-activate reset for next frame */
        if (sbr->ret && sbr->Reset)
            sbr->bs_start_freq_prev = -1;
    }

    if (just_seeked)
    {
        sbr->just_seeked = 1;
    } else {
        sbr->just_seeked = 0;
    }

    sbr_process_channel(sbr, left_channel, p_XLR->X_L, 0, dont_process, downSampledSBR);

    /* copy some extra data for PS */
    for (l = 32; l < 38; l++)
    {
        for (k = 0; k < 5; k++)
        {
            QMF_RE(p_XLR->X_L[l][k]) = QMF_RE(sbr->Xsbr[0][sbr->tHFAdj+l][k]);
            QMF_IM(p_XLR->X_L[l][k]) = QMF_IM(sbr->Xsbr[0][sbr->tHFAdj+l][k]);
        }
    }

    /* perform parametric stereo */
#ifdef DRM_PS
    if (sbr->Is_DRM_SBR)
    {
        drm_ps_decode(sbr->drm_ps, (sbr->ret > 0), sbr->sample_rate, p_XLR->X_L, p_XLR->X_R);
    } else {
#endif
#ifdef PS_DEC
        ps_decode(&sbr->ps, p_XLR->X_L, p_XLR->X_R);
#endif
#ifdef DRM_PS
    }
#endif

    /* subband synthesis */
    if (downSampledSBR)
    {
        sbr_qmf_synthesis_32(sbr, &sbr->qmfs[0], p_XLR->X_L, left_channel);
        sbr_qmf_synthesis_32(sbr, &sbr->qmfs[1], p_XLR->X_R, right_channel);
    } else {
        sbr_qmf_synthesis_64(sbr, &sbr->qmfs[0], p_XLR->X_L, left_channel);
        sbr_qmf_synthesis_64(sbr, &sbr->qmfs[1], p_XLR->X_R, right_channel);
    }

    if (sbr->bs_header_flag)
        sbr->just_seeked = 0;

    if (sbr->header_count != 0 && sbr->ret == 0)
    {
        ret = sbr_save_prev_data(sbr, 0);
        if (ret) return ret;
    }

    sbr_save_matrix(sbr, 0);

    sbr->frame++;

    return 0;
}
uint8_t sbrDecodeSingleFramePS(sbr_info *sbr, real_t *left_channel, real_t *right_channel,
                               const uint8_t just_seeked, const uint8_t downSampledSBR)
{
    uint8_t l, k;
    uint8_t dont_process = 0;
    uint8_t ret = 0;
    ALIGN qmf_t X_left[38][64] = {{0}};
    ALIGN qmf_t X_right[38][64] = {{0}}; /* must set this to 0 */

    if (sbr == NULL)
        return 20;

    /* case can occur due to bit errors */
    if (sbr->id_aac != ID_SCE && sbr->id_aac != ID_LFE)
        return 21;

    if (sbr->ret || (sbr->header_count == 0))
    {
        /* don't process just upsample */
        dont_process = 1;

        /* Re-activate reset for next frame */
        if (sbr->ret && sbr->Reset)
            sbr->bs_start_freq_prev = -1;
    }

    if (just_seeked)
    {
        sbr->just_seeked = 1;
    } else {
        sbr->just_seeked = 0;
    }

    if (sbr->qmfs[1] == NULL)
    {
        sbr->qmfs[1] = qmfs_init((downSampledSBR)?32:64);
    }

    sbr->ret += sbr_process_channel(sbr, left_channel, X_left, 0, dont_process, downSampledSBR);

    /* copy some extra data for PS */
    for (l = sbr->numTimeSlotsRate; l < sbr->numTimeSlotsRate + 6; l++)
    {
        for (k = 0; k < 5; k++)
        {
            QMF_RE(X_left[l][k]) = QMF_RE(sbr->Xsbr[0][sbr->tHFAdj+l][k]);
            QMF_IM(X_left[l][k]) = QMF_IM(sbr->Xsbr[0][sbr->tHFAdj+l][k]);
        }
    }

    /* perform parametric stereo */
#ifdef DRM_PS
    if (sbr->Is_DRM_SBR)
    {
        drm_ps_decode(sbr->drm_ps, (sbr->ret > 0), X_left, X_right);
    } else {
#endif
#ifdef PS_DEC
        ps_decode(sbr->ps, X_left, X_right);
#endif
#ifdef DRM_PS
    }
#endif

    /* subband synthesis */
    if (downSampledSBR)
    {
        sbr_qmf_synthesis_32(sbr, sbr->qmfs[0], X_left, left_channel);
        sbr_qmf_synthesis_32(sbr, sbr->qmfs[1], X_right, right_channel);
    } else {
        sbr_qmf_synthesis_64(sbr, sbr->qmfs[0], X_left, left_channel);
        sbr_qmf_synthesis_64(sbr, sbr->qmfs[1], X_right, right_channel);
    }

    if (sbr->bs_header_flag)
        sbr->just_seeked = 0;

    if (sbr->header_count != 0 && sbr->ret == 0)
    {
        ret = sbr_save_prev_data(sbr, 0);
        if (ret) return ret;
    }

    sbr_save_matrix(sbr, 0);

    sbr->frame++;

    return 0;
}
예제 #9
0
void sbrDecodeFrame(sbr_info *sbr, real_t *left_channel,
                    real_t *right_channel, uint8_t id_aac,
                    uint8_t just_seeked)
{
 int16_t i, k, l;

 uint8_t dont_process = 0;
 uint8_t ch, channels, ret;
 real_t *ch_buf;

 sbr->id_aac = id_aac;
 channels = (id_aac == ID_SCE) ? 1 : 2;

 ret = sbr_extension_data(&sbr->ld, sbr, id_aac);

 ret = (sbr->ld.error)? sbr->ld.error : ret;

 if(ret || (sbr->header_count == 0))
  dont_process = 1;

 if(just_seeked)
  sbr->just_seeked = 1;
 else
  sbr->just_seeked = 0;

 for (ch = 0; ch < channels; ch++){
  if (ch == 0)
   ch_buf = left_channel;
  else
   ch_buf = right_channel;

  for (i = 0; i < tHFAdj; i++){
   int8_t j;
   for (j = sbr->kx_prev; j < sbr->kx; j++){
    QMF_RE(sbr->Xcodec[ch][i*32 + j]) = 0;
    QMF_IM(sbr->Xcodec[ch][i*32 + j]) = 0;
   }
  }

  sbr_qmf_analysis_32(sbr->qmfa[ch], ch_buf, sbr->Xcodec[ch], tHFGen);

  if(!dont_process){
   hf_generation(sbr, sbr->Xcodec[ch], sbr->Xsbr[ch],ch);
   hf_adjustment(sbr, sbr->Xsbr[ch],ch);
  }

  if((sbr->just_seeked != 0) || dont_process){
   for (l = 0; l < 32; l++){
    for (k = 0; k < 32; k++){
     QMF_RE(sbr->temp_X[l * 64 + k]) = QMF_RE(sbr->Xcodec[ch][(l + tHFAdj)*32 + k]);
     QMF_IM(sbr->temp_X[l * 64 + k]) = QMF_IM(sbr->Xcodec[ch][(l + tHFAdj)*32 + k]);
    }
    for (k = 32; k < 64; k++){
     QMF_RE(sbr->temp_X[l * 64 + k]) = 0;
     QMF_IM(sbr->temp_X[l * 64 + k]) = 0;
    }
   }
  }else{
   for (l = 0; l < 32; l++){
    uint8_t xover_band;

    if (l < sbr->t_E[ch][0])
     xover_band = sbr->kx_prev;
    else
     xover_band = sbr->kx;

    for (k = 0; k < xover_band; k++){
     QMF_RE(sbr->temp_X[l * 64 + k]) = QMF_RE(sbr->Xcodec[ch][(l + tHFAdj)*32 + k]);
     QMF_IM(sbr->temp_X[l * 64 + k]) = QMF_IM(sbr->Xcodec[ch][(l + tHFAdj)*32 + k]);
    }
    for (k = xover_band; k < 64; k++){
     QMF_RE(sbr->temp_X[l * 64 + k]) = QMF_RE(sbr->Xsbr[ch][(l + tHFAdj)*64 + k]);
     QMF_IM(sbr->temp_X[l * 64 + k]) = QMF_IM(sbr->Xsbr[ch][(l + tHFAdj)*64 + k]);
    }
   }
  }

  sbr_qmf_synthesis_64(sbr->qmfs[ch], (const complex_t*)sbr->temp_X, ch_buf);

  for (i = 0; i < 32; i++){
   int8_t j;
   for (j = 0; j < tHFGen; j++){
    QMF_RE(sbr->Xcodec[ch][j*32 + i]) = QMF_RE(sbr->Xcodec[ch][(j+32)*32 + i]);
    QMF_IM(sbr->Xcodec[ch][j*32 + i]) = QMF_IM(sbr->Xcodec[ch][(j+32)*32 + i]);
   }
  }
  for (i = 0; i < 64; i++){
   int8_t j;
   for (j = 0; j < tHFGen; j++){
    QMF_RE(sbr->Xsbr[ch][j*64 + i]) = QMF_RE(sbr->Xsbr[ch][(j+32)*64 + i]);
    QMF_IM(sbr->Xsbr[ch][j*64 + i]) = QMF_IM(sbr->Xsbr[ch][(j+32)*64 + i]);
   }
  }
 }

 if (sbr->bs_header_flag)
  sbr->just_seeked = 0;

 if (sbr->header_count != 0){
  for (ch = 0; ch < channels; ch++)
   sbr_save_prev_data(sbr, ch);
 }

 sbr->frame++;
}
예제 #10
0
static void hf_assembly(sbr_info *sbr, sbr_hfadj_info *adj,
                        qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch)
{
    static real_t h_smooth[] = {
        COEF_CONST(0.03183050093751), COEF_CONST(0.11516383427084),
        COEF_CONST(0.21816949906249), COEF_CONST(0.30150283239582),
        COEF_CONST(0.33333333333333)
    };
    static int8_t phi_re[] = { 1, 0, -1, 0 };
    static int8_t phi_im[] = { 0, 1, 0, -1 };

    uint8_t m, l, i, n;
    uint16_t fIndexNoise = 0;
    uint8_t fIndexSine = 0;
    uint8_t assembly_reset = 0;
    real_t *temp;

    real_t G_filt, Q_filt;

    uint8_t h_SL;


    if (sbr->Reset == 1)
    {
        assembly_reset = 1;
        fIndexNoise = 0;
    } else {
        fIndexNoise = sbr->index_noise_prev[ch];
    }
    fIndexSine = sbr->psi_is_prev[ch];


    for (l = 0; l < sbr->L_E[ch]; l++)
    {
        uint8_t no_noise = (l == sbr->l_A[ch] || l == sbr->prevEnvIsShort[ch]) ? 1 : 0;

#ifdef SBR_LOW_POWER
        h_SL = 0;
#else
        h_SL = (sbr->bs_smoothing_mode == 1) ? 0 : 4;
        h_SL = (no_noise ? 0 : h_SL);
#endif

        if (assembly_reset)
        {
            for (n = 0; n < 4; n++)
            {
                memcpy(sbr->G_temp_prev[ch][n], adj->G_lim_boost[l], sbr->M*sizeof(real_t));
                memcpy(sbr->Q_temp_prev[ch][n], adj->Q_M_lim_boost[l], sbr->M*sizeof(real_t));
            }
            assembly_reset = 0;
        }

        for (i = sbr->t_E[ch][l]; i < sbr->t_E[ch][l+1]; i++)
        {
#ifdef SBR_LOW_POWER
            uint8_t i_min1, i_plus1;
            uint8_t sinusoids = 0;
#endif

            memcpy(sbr->G_temp_prev[ch][4], adj->G_lim_boost[l], sbr->M*sizeof(real_t));
            memcpy(sbr->Q_temp_prev[ch][4], adj->Q_M_lim_boost[l], sbr->M*sizeof(real_t));

            for (m = 0; m < sbr->M; m++)
            {
                uint8_t j;
                qmf_t psi;


                G_filt = 0;
                Q_filt = 0;
                j = 0;

                if (h_SL != 0)
                {
                    for (n = 0; n <= 4; n++)
                    {
                        G_filt += MUL_C(sbr->G_temp_prev[ch][n][m], h_smooth[j]);
                        Q_filt += MUL_C(sbr->Q_temp_prev[ch][n][m], h_smooth[j]);
                        j++;
                    }
                } else {
                    G_filt = sbr->G_temp_prev[ch][4][m];
                    Q_filt = sbr->Q_temp_prev[ch][4][m];
                }

                Q_filt = (adj->S_M_boost[l][m] != 0 || no_noise) ? 0 : Q_filt;

                /* add noise to the output */
                fIndexNoise = (fIndexNoise + 1) & 511;

                /* the smoothed gain values are applied to Xsbr */
                /* V is defined, not calculated */
                QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) = MUL_R(G_filt, QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]))
                    + MUL_F(Q_filt, RE(V[fIndexNoise]));
                if (sbr->bs_extension_id == 3 && sbr->bs_extension_data == 42)
                    QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) = 16428320;
#ifndef SBR_LOW_POWER
                QMF_IM(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) = MUL_R(G_filt, QMF_IM(Xsbr[i + sbr->tHFAdj][m+sbr->kx]))
                    + MUL_F(Q_filt, IM(V[fIndexNoise]));
#endif

                //if (adj->S_index_mapped[m][l])
                {
                    int8_t rev = (((m + sbr->kx) & 1) ? -1 : 1);
                    QMF_RE(psi) = MUL_R(adj->S_M_boost[l][m], phi_re[fIndexSine]);
                    QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) += QMF_RE(psi);

#ifndef SBR_LOW_POWER
                    QMF_IM(psi) = rev * MUL_R(adj->S_M_boost[l][m], phi_im[fIndexSine]);
                    QMF_IM(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) += QMF_IM(psi);
#else
                    i_min1 = (fIndexSine - 1) & 3;
                    i_plus1 = (fIndexSine + 1) & 3;

                    if (m == 0)
                    {
                        QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx - 1]) -=
                            (-1*rev * MUL_C(MUL_R(adj->S_M_boost[l][0], phi_re[i_plus1]), COEF_CONST(0.00815)));
                        if(m < sbr->M - 1)
                        {
                            QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) -=
                                (rev * MUL_C(MUL_R(adj->S_M_boost[l][1], phi_re[i_plus1]), COEF_CONST(0.00815)));
                        }
                    }
                    if ((m > 0) && (m < sbr->M - 1) && (sinusoids < 16))
                    {
                        QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) -=
                            (rev * MUL_C(MUL_R(adj->S_M_boost[l][m - 1], phi_re[i_min1]), COEF_CONST(0.00815)));
                        QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) -=
                            (rev * MUL_C(MUL_R(adj->S_M_boost[l][m + 1], phi_re[i_plus1]), COEF_CONST(0.00815)));
                    }
                    if ((m == sbr->M - 1) && (sinusoids < 16))
                    {
                        if (m > 0)
                        {
                            QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx]) -=
                                (rev * MUL_C(MUL_R(adj->S_M_boost[l][m - 1], phi_re[i_min1]), COEF_CONST(0.00815)));
                        }
                        if (m + sbr->kx < 64)
                        {
                            QMF_RE(Xsbr[i + sbr->tHFAdj][m+sbr->kx + 1]) -=
                                (-1*rev * MUL_C(MUL_R(adj->S_M_boost[l][m], phi_re[i_min1]), COEF_CONST(0.00815)));
                        }
                    }

                    if (adj->S_M_boost[l][m] != 0)
                        sinusoids++;
#endif
                }
            }

            fIndexSine = (fIndexSine + 1) & 3;


            temp = sbr->G_temp_prev[ch][0];
            for (n = 0; n < 4; n++)
                sbr->G_temp_prev[ch][n] = sbr->G_temp_prev[ch][n+1];
            sbr->G_temp_prev[ch][4] = temp;

            temp = sbr->Q_temp_prev[ch][0];
            for (n = 0; n < 4; n++)
                sbr->Q_temp_prev[ch][n] = sbr->Q_temp_prev[ch][n+1];
            sbr->Q_temp_prev[ch][4] = temp;
        }
    }

    sbr->index_noise_prev[ch] = fIndexNoise;
    sbr->psi_is_prev[ch] = fIndexSine;
}
예제 #11
0
static void estimate_current_envelope(sbr_info *sbr, sbr_hfadj_info *adj,
                                      qmf_t Xsbr[MAX_NTSRHFG][64], uint8_t ch)
{
    uint8_t m, l, j, k, k_l, k_h, p;
    real_t nrg, div;

    if (sbr->bs_interpol_freq == 1)
    {
        for (l = 0; l < sbr->L_E[ch]; l++)
        {
            uint8_t i, l_i, u_i;

            l_i = sbr->t_E[ch][l];
            u_i = sbr->t_E[ch][l+1];

            div = (real_t)(u_i - l_i);

            for (m = 0; m < sbr->M; m++)
            {
                nrg = 0;

                for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++)
                {
                    nrg += MUL_R(QMF_RE(Xsbr[i][m + sbr->kx]), QMF_RE(Xsbr[i][m + sbr->kx]))
#ifndef SBR_LOW_POWER
                        + MUL_R(QMF_IM(Xsbr[i][m + sbr->kx]), QMF_IM(Xsbr[i][m + sbr->kx]))
#endif
                        ;
                }

                sbr->E_curr[ch][m][l] = nrg / div;
#ifdef SBR_LOW_POWER
                sbr->E_curr[ch][m][l] *= 2;
#endif
            }
        }
    } else {
        for (l = 0; l < sbr->L_E[ch]; l++)
        {
            for (p = 0; p < sbr->n[sbr->f[ch][l]]; p++)
            {
                k_l = sbr->f_table_res[sbr->f[ch][l]][p];
                k_h = sbr->f_table_res[sbr->f[ch][l]][p+1];

                for (k = k_l; k < k_h; k++)
                {
                    uint8_t i, l_i, u_i;
                    nrg = 0.0;

                    l_i = sbr->t_E[ch][l];
                    u_i = sbr->t_E[ch][l+1];

                    div = (real_t)((u_i - l_i)*(k_h - k_l));

                    for (i = l_i + sbr->tHFAdj; i < u_i + sbr->tHFAdj; i++)
                    {
                        for (j = k_l; j < k_h; j++)
                        {
                            nrg += MUL_R(QMF_RE(Xsbr[i][j]), QMF_RE(Xsbr[i][j]))
#ifndef SBR_LOW_POWER
                                + MUL_R(QMF_IM(Xsbr[i][j]), QMF_IM(Xsbr[i][j]))
#endif
                                ;
                        }
                    }

                    sbr->E_curr[ch][k - sbr->kx][l] = nrg / div;
#ifdef SBR_LOW_POWER
                    sbr->E_curr[ch][k - sbr->kx][l] *= 2;
#endif
                }
            }
        }
    }
}
예제 #12
0
void hf_generation(sbr_info *sbr, qmf_t Xlow[MAX_NTSRHFG][32],
                   qmf_t Xhigh[MAX_NTSRHFG][64]
#ifdef SBR_LOW_POWER
                   ,real_t *deg
#endif
                   ,uint8_t ch)
{
    uint8_t l, i, x;
    ALIGN complex_t alpha_0[64], alpha_1[64];
#ifdef SBR_LOW_POWER
    ALIGN real_t rxx[64];
#endif

    uint8_t offset = sbr->tHFAdj;
    uint8_t first = sbr->t_E[ch][0];
    uint8_t last = sbr->t_E[ch][sbr->L_E[ch]];

//    printf("%d %d\n", first, last);

    calc_chirp_factors(sbr, ch);

    for (i = first; i < last; i++)
    {
        memset(Xhigh[i + offset], 0, 64 * sizeof(qmf_t));
    }

    if ((ch == 0) && (sbr->Reset))
        patch_construction(sbr);

    /* calculate the prediction coefficients */
    calc_prediction_coef(sbr, Xlow, alpha_0, alpha_1
#ifdef SBR_LOW_POWER
        , rxx
#endif
        );

#ifdef SBR_LOW_POWER
    calc_aliasing_degree(sbr, rxx, deg);
#endif

    /* actual HF generation */
    for (i = 0; i < sbr->noPatches; i++)
    {
        for (x = 0; x < sbr->patchNoSubbands[i]; x++)
        {
            complex_t a0, a1;
            real_t bw, bw2;
            uint8_t q, p, k, g;

            /* find the low and high band for patching */
            k = sbr->kx + x;
            for (q = 0; q < i; q++)
            {
                k += sbr->patchNoSubbands[q];
            }
            p = sbr->patchStartSubband[i] + x;

#ifdef SBR_LOW_POWER
            if (x != 0 /*x < sbr->patchNoSubbands[i]-1*/)
                deg[k] = deg[p];
            else
                deg[k] = 0;
#endif

            g = sbr->table_map_k_to_g[k];

            bw = sbr->bwArray[ch][g];
            bw2 = MUL_C(bw, bw);

            /* do the patching */
            /* with or without filtering */
            if (bw2 > 0)
            {
                RE(a0) = MUL_C(RE(alpha_0[p]), bw);
                RE(a1) = MUL_C(RE(alpha_1[p]), bw2);
#ifndef SBR_LOW_POWER
                IM(a0) = MUL_C(IM(alpha_0[p]), bw);
                IM(a1) = MUL_C(IM(alpha_1[p]), bw2);
#endif

				for (l = first; l < last; l++)
                {
                    QMF_RE(Xhigh[l + offset][k]) = QMF_RE(Xlow[l + offset][p]);
#ifndef SBR_LOW_POWER
                    QMF_IM(Xhigh[l + offset][k]) = QMF_IM(Xlow[l + offset][p]);
#endif

#ifdef SBR_LOW_POWER
                    QMF_RE(Xhigh[l + offset][k]) += (
                        MUL_R(RE(a0), QMF_RE(Xlow[l - 1 + offset][p])) +
                        MUL_R(RE(a1), QMF_RE(Xlow[l - 2 + offset][p])));
#else
                    QMF_RE(Xhigh[l + offset][k]) += (
                        RE(a0) * QMF_RE(Xlow[l - 1 + offset][p]) -
                        IM(a0) * QMF_IM(Xlow[l - 1 + offset][p]) +
                        RE(a1) * QMF_RE(Xlow[l - 2 + offset][p]) -
                        IM(a1) * QMF_IM(Xlow[l - 2 + offset][p]));
                    QMF_IM(Xhigh[l + offset][k]) += (
                        IM(a0) * QMF_RE(Xlow[l - 1 + offset][p]) +
                        RE(a0) * QMF_IM(Xlow[l - 1 + offset][p]) +
                        IM(a1) * QMF_RE(Xlow[l - 2 + offset][p]) +
                        RE(a1) * QMF_IM(Xlow[l - 2 + offset][p]));
#endif
                }
            } else {
                for (l = first; l < last; l++)
                {
                    QMF_RE(Xhigh[l + offset][k]) = QMF_RE(Xlow[l + offset][p]);
#ifndef SBR_LOW_POWER
                    QMF_IM(Xhigh[l + offset][k]) = QMF_IM(Xlow[l + offset][p]);
#endif
                }
            }
        }
    }

    if (sbr->Reset)
    {
        limiter_frequency_table(sbr);
    }
}
예제 #13
0
static void auto_correlation(sbr_info *sbr, acorr_coef *ac, qmf_t buffer[MAX_NTSRHFG][32],
                             uint8_t bd, uint8_t len)
{
    real_t r01r = 0, r01i = 0, r02r = 0, r02i = 0, r11r = 0;
    const real_t rel = 1 / (1 + 1e-6f);
    int8_t j;
    uint8_t offset = sbr->tHFAdj;


    for (j = offset; j < len + offset; j++)
    {
        r01r += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j-1][bd]) +
            QMF_IM(buffer[j][bd]) * QMF_IM(buffer[j-1][bd]);
        r01i += QMF_IM(buffer[j][bd]) * QMF_RE(buffer[j-1][bd]) -
            QMF_RE(buffer[j][bd]) * QMF_IM(buffer[j-1][bd]);
        r02r += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j-2][bd]) +
            QMF_IM(buffer[j][bd]) * QMF_IM(buffer[j-2][bd]);
        r02i += QMF_IM(buffer[j][bd]) * QMF_RE(buffer[j-2][bd]) -
            QMF_RE(buffer[j][bd]) * QMF_IM(buffer[j-2][bd]);
        r11r += QMF_RE(buffer[j-1][bd]) * QMF_RE(buffer[j-1][bd]) +
            QMF_IM(buffer[j-1][bd]) * QMF_IM(buffer[j-1][bd]);
    }

    RE(ac->r01) = r01r;
    IM(ac->r01) = r01i;
    RE(ac->r02) = r02r;
    IM(ac->r02) = r02i;
    RE(ac->r11) = r11r;

    RE(ac->r12) = r01r -
        (QMF_RE(buffer[len+offset-1][bd]) * QMF_RE(buffer[len+offset-2][bd]) + QMF_IM(buffer[len+offset-1][bd]) * QMF_IM(buffer[len+offset-2][bd])) +
        (QMF_RE(buffer[offset-1][bd]) * QMF_RE(buffer[offset-2][bd]) + QMF_IM(buffer[offset-1][bd]) * QMF_IM(buffer[offset-2][bd]));
    IM(ac->r12) = r01i -
        (QMF_IM(buffer[len+offset-1][bd]) * QMF_RE(buffer[len+offset-2][bd]) - QMF_RE(buffer[len+offset-1][bd]) * QMF_IM(buffer[len+offset-2][bd])) +
        (QMF_IM(buffer[offset-1][bd]) * QMF_RE(buffer[offset-2][bd]) - QMF_RE(buffer[offset-1][bd]) * QMF_IM(buffer[offset-2][bd]));
    RE(ac->r22) = r11r -
        (QMF_RE(buffer[len+offset-2][bd]) * QMF_RE(buffer[len+offset-2][bd]) + QMF_IM(buffer[len+offset-2][bd]) * QMF_IM(buffer[len+offset-2][bd])) +
        (QMF_RE(buffer[offset-2][bd]) * QMF_RE(buffer[offset-2][bd]) + QMF_IM(buffer[offset-2][bd]) * QMF_IM(buffer[offset-2][bd]));

    ac->det = RE(ac->r11) * RE(ac->r22) - rel * (RE(ac->r12) * RE(ac->r12) + IM(ac->r12) * IM(ac->r12));
}
예제 #14
0
static void auto_correlation(sbr_info *sbr, acorr_coef *ac,
                             qmf_t buffer[MAX_NTSRHFG][32],
                             uint8_t bd, uint8_t len)
{
    real_t r01 = 0, r02 = 0, r11 = 0;
    int8_t j;
    uint8_t offset = sbr->tHFAdj;
    const real_t rel = 1 / (1 + 1e-6f);


    for (j = offset; j < len + offset; j++)
    {
        r01 += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j-1][bd]);
        r02 += QMF_RE(buffer[j][bd]) * QMF_RE(buffer[j-2][bd]);
        r11 += QMF_RE(buffer[j-1][bd]) * QMF_RE(buffer[j-1][bd]);
    }
    RE(ac->r12) = r01 -
        QMF_RE(buffer[len+offset-1][bd]) * QMF_RE(buffer[len+offset-2][bd]) +
        QMF_RE(buffer[offset-1][bd]) * QMF_RE(buffer[offset-2][bd]);
    RE(ac->r22) = r11 -
        QMF_RE(buffer[len+offset-2][bd]) * QMF_RE(buffer[len+offset-2][bd]) +
        QMF_RE(buffer[offset-2][bd]) * QMF_RE(buffer[offset-2][bd]);
    RE(ac->r01) = r01;
    RE(ac->r02) = r02;
    RE(ac->r11) = r11;

    ac->det = MUL_R(RE(ac->r11), RE(ac->r22)) - MUL_C(MUL_R(RE(ac->r12), RE(ac->r12)), rel);
}