Home | History | Annotate | Download | only in decoder
      1 /******************************************************************************
      2  *                                                                            *
      3  * Copyright (C) 2018 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at:
      8  *
      9  * http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  *
     17  *****************************************************************************
     18  * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
     19 */
     20 #include <ixheaacd_type_def.h>
     21 #include "ixheaacd_bitbuffer.h"
     22 #include "ixheaacd_config.h"
     23 
     24 #include "ixheaacd_mps_polyphase.h"
     25 
     26 #include "ixheaacd_mps_dec.h"
     27 #include "ixheaacd_mps_interface.h"
     28 #include <math.h>
     29 
     30 #define max(a, b) ((a) > (b) ? (a) : (b))
     31 
     32 #define min(a, b) ((a) < (b) ? (a) : (b))
     33 
     34 #define DIR_DIFF_IN 0
     35 #define DOWNMIX_IN 1
     36 
     37 #define LAMDA (4.0f)
     38 #define GES_ALPHA (0.99637864f)
     39 #define GES_BETA (0.9643691f)
     40 
     41 extern WORD32
     42     ixheaacd_hybrid_band_71_to_processing_band_20_map[MAX_HYBRID_BANDS_MPS];
     43 
     44 VOID ixheaacd_mps_env_init(ia_mps_dec_state_struct *self) {
     45   WORD32 i;
     46   for (i = 0; i < 3; i++) {
     47     self->guided_env_shaping.avg_energy_prev[i] = 32768.f * 32768.f;
     48   }
     49 }
     50 
     51 static VOID ixheaacd_mps_est_normalized_envelope(ia_mps_dec_state_struct *self,
     52                                                  WORD32 inp, WORD32 ch,
     53                                                  FLOAT32 *env) {
     54   FLOAT32 slot_energy[MAX_TIME_SLOTS][MAX_PARAMETER_BANDS] = {{0}};
     55   FLOAT32 pb_energy[MAX_PARAMETER_BANDS] = {0};
     56   FLOAT32 whitening_weight[MAX_PARAMETER_BANDS];
     57   WORD32 ii, jj, param_band;
     58 
     59   WORD32 k_start = 10;
     60   WORD32 k_stop = 18;
     61 
     62   FLOAT32 total_energy = 0, avg_energy = 0;
     63 
     64   WORD32 ch_offset;
     65 
     66   switch (inp) {
     67     case DIR_DIFF_IN:
     68       ch_offset = 0;
     69       for (ii = 0; ii < self->time_slots; ii++) {
     70         for (jj = 0; jj < self->hyb_band_count; jj++) {
     71           slot_energy[ii]
     72                      [ixheaacd_hybrid_band_71_to_processing_band_20_map[jj]] +=
     73               ((self->hyb_dir_out[ch][ii][jj].re +
     74                 self->hyb_diff_out[ch][ii][jj].re) *
     75                (self->hyb_dir_out[ch][ii][jj].re +
     76                 self->hyb_diff_out[ch][ii][jj].re)) +
     77               ((self->hyb_dir_out[ch][ii][jj].im +
     78                 self->hyb_diff_out[ch][ii][jj].im) *
     79                (self->hyb_dir_out[ch][ii][jj].im +
     80                 self->hyb_diff_out[ch][ii][jj].im));
     81         }
     82       }
     83       break;
     84     case DOWNMIX_IN:
     85       ch_offset = self->out_ch_count;
     86       for (ii = 0; ii < self->time_slots; ii++) {
     87         for (jj = 0; jj < self->hyb_band_count; jj++) {
     88           slot_energy[ii]
     89                      [ixheaacd_hybrid_band_71_to_processing_band_20_map[jj]] +=
     90               self->hyb_in[ch][ii][jj].re * self->hyb_in[ch][ii][jj].re +
     91               self->hyb_in[ch][ii][jj].im * self->hyb_in[ch][ii][jj].im;
     92         }
     93       }
     94       break;
     95     default:
     96       ch_offset = 0;
     97       break;
     98   }
     99 
    100   for (param_band = k_start; param_band <= k_stop; param_band++)
    101     pb_energy[param_band] =
    102         self->guided_env_shaping.pb_energy_prev[ch + ch_offset][param_band];
    103 
    104   avg_energy = self->guided_env_shaping.avg_energy_prev[ch + ch_offset];
    105 
    106   for (ii = 0; ii < self->time_slots; ii++) {
    107     total_energy = 0;
    108     for (param_band = k_start; param_band <= k_stop; param_band++) {
    109       pb_energy[param_band] = (1 - GES_ALPHA) * slot_energy[ii][param_band] +
    110                               GES_ALPHA * pb_energy[param_band];
    111 
    112       total_energy += slot_energy[ii][param_band];
    113     }
    114     total_energy /= (k_stop - k_start + 1);
    115 
    116     total_energy =
    117         (1 - GES_ALPHA) * total_energy +
    118         GES_ALPHA * self->guided_env_shaping.frame_energy_prev[ch + ch_offset];
    119 
    120     self->guided_env_shaping.frame_energy_prev[ch + ch_offset] = total_energy;
    121 
    122     for (param_band = k_start; param_band <= k_stop; param_band++) {
    123       whitening_weight[param_band] =
    124           total_energy / (pb_energy[param_band] + ABS_THR);
    125     }
    126 
    127     env[ii] = 0;
    128     for (param_band = k_start; param_band <= k_stop; param_band++) {
    129       env[ii] += slot_energy[ii][param_band] * whitening_weight[param_band];
    130     }
    131 
    132     avg_energy = (1 - GES_BETA) * env[ii] + GES_BETA * avg_energy;
    133 
    134     env[ii] = (FLOAT32)sqrt(env[ii] / (avg_energy + ABS_THR));
    135   }
    136 
    137   for (param_band = k_start; param_band <= k_stop; param_band++)
    138     self->guided_env_shaping.pb_energy_prev[ch + ch_offset][param_band] =
    139         pb_energy[param_band];
    140 
    141   self->guided_env_shaping.avg_energy_prev[ch + ch_offset] = avg_energy;
    142 }
    143 
    144 VOID ixheaacd_mps_time_env_shaping(ia_mps_dec_state_struct *self) {
    145   FLOAT32 dir_energy[MAX_TIME_SLOTS];
    146   FLOAT32 dmx_energy[MAX_TIME_SLOTS];
    147   WORD32 ch, time_slot, jj;
    148 
    149   WORD32 band_start;
    150   FLOAT32 gain, ratio;
    151 
    152   FLOAT32 amp_direct = 0;
    153   FLOAT32 amp_diff = 0;
    154   FLOAT32 amp_ratio;
    155 
    156   band_start = 6;
    157 
    158   ixheaacd_mps_est_normalized_envelope(self, DOWNMIX_IN, 0, dmx_energy);
    159 
    160   for (ch = 0; ch < self->out_ch_count; ch++) {
    161     ixheaacd_mps_est_normalized_envelope(self, DIR_DIFF_IN, ch, dir_energy);
    162 
    163     if (self->temp_shape_enable_ch_ges[ch]) {
    164       for (time_slot = 0; time_slot < self->time_slots; time_slot++) {
    165         gain = self->env_shape_data[ch][time_slot] * dmx_energy[time_slot] /
    166                (dir_energy[time_slot] + 1e-9f);
    167 
    168         amp_direct = 0;
    169         amp_diff = 0;
    170 
    171         for (jj = band_start; jj < self->hyb_band_count; jj++) {
    172           amp_direct += self->hyb_dir_out[ch][time_slot][jj].re *
    173                             self->hyb_dir_out[ch][time_slot][jj].re +
    174                         self->hyb_dir_out[ch][time_slot][jj].im *
    175                             self->hyb_dir_out[ch][time_slot][jj].im;
    176 
    177           amp_diff += self->hyb_diff_out[ch][time_slot][jj].re *
    178                           self->hyb_diff_out[ch][time_slot][jj].re +
    179                       self->hyb_diff_out[ch][time_slot][jj].im *
    180                           self->hyb_diff_out[ch][time_slot][jj].im;
    181         }
    182 
    183         amp_ratio = (FLOAT32)sqrt(amp_diff / (amp_direct + ABS_THR));
    184 
    185         ratio = min(max((gain + amp_ratio * (gain - 1)), 1 / LAMDA), LAMDA);
    186 
    187         for (jj = band_start; jj < self->hyb_band_count; jj++) {
    188           self->hyb_dir_out[ch][time_slot][jj].re *= ratio;
    189           self->hyb_dir_out[ch][time_slot][jj].im *= ratio;
    190         }
    191       }
    192     }
    193   }
    194 }
    195