blob: 7eec5a909b1c9d080730c410dc78d43f4d70b3e9 [file] [edit]
/******************************************************************************
* *
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*****************************************************************************
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
#include <math.h>
#include "ixheaac_type_def.h"
#include "ixheaac_constants.h"
#include "ixheaace_error_codes.h"
#include "ixheaac_error_standards.h"
#include "ixheaace_aac_constants.h"
#include "ixheaac_basic_ops32.h"
#include "ixheaac_basic_ops16.h"
#include "ixheaac_basic_ops40.h"
#include "ixheaac_basic_ops.h"
#include "ixheaace_common_rom.h"
#include "ixheaace_sbr_header.h"
#include "ixheaace_sbr_def.h"
#include "ixheaace_sbr_freq_scaling.h"
#include "ixheaace_sbr_misc.h"
#include "ixheaace_resampler.h"
#include "ixheaace_sbr_rom.h"
static WORD32 ixheaace_get_start_freq_4_1(WORD32 fs, WORD32 start_freq) {
WORD32 minimum_k0;
const WORD32 *ptr_start_offset;
switch (fs) {
case 16000:
minimum_k0 = 12;
break;
case 22050:
minimum_k0 = 9;
break;
case 24000:
minimum_k0 = 8;
break;
case 32000:
minimum_k0 = 8;
break;
case 44100:
minimum_k0 = 6;
break;
case 48000:
minimum_k0 = 5;
break;
default:
minimum_k0 = 5; /* illegal fs */
}
switch (fs) {
case 16000: {
ptr_start_offset = &ixheaace_start_freq_16k_4_1[0];
} break;
case 22050: {
ptr_start_offset = &ixheaace_start_freq_22k_4_1[0];
} break;
case 24000: {
ptr_start_offset = &ixheaace_start_freq_24k_4_1[0];
} break;
case 32000: {
ptr_start_offset = &ixheaace_start_freq_32k_4_1[0];
} break;
case 44100:
case 48000:
case 64000: {
ptr_start_offset = &ixheaace_start_freq_48k_4_1[0];
} break;
case 88200:
case 96000: {
ptr_start_offset = &ixheaace_start_freq_96k_4_1[0];
} break;
default: {
ptr_start_offset = &ixheaace_start_freq_dflt_4_1[0];
}
}
return (minimum_k0 + ptr_start_offset[start_freq]);
}
static WORD32 ixheaace_get_stop_freq_4_1(WORD32 fs, WORD32 stop_freq) {
WORD32 result, i;
WORD32 *v_stop_freq = 0;
WORD32 k1_min;
WORD32 v_dstop[13];
/* counting previous operations */
switch (fs) {
case 16000:
k1_min = 24;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_16k_4_1[0];
break;
case 22050:
k1_min = 17;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_22k_4_1[0];
break;
case 24000:
k1_min = 16;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_24k_4_1[0];
break;
case 32000:
k1_min = 16;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_32k_4_1[0];
break;
case 44100:
k1_min = 12;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_44k_4_1[0];
break;
case 48000:
k1_min = 11;
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_48k_4_1[0];
break;
default:
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_32k_4_1[0];
k1_min = 11; /* illegal fs */
}
for (i = 0; i <= 12; i++) {
v_dstop[i] = v_stop_freq[i + 1] - v_stop_freq[i];
}
ixheaace_shellsort_int(v_dstop, 13);
result = k1_min;
for (i = 0; i < stop_freq; i++) {
result = result + v_dstop[i];
}
return result;
}
static WORD32 ixheaace_get_start_freq(WORD32 fs, WORD32 start_freq) {
WORD32 minimum_k0;
switch (fs) {
case 16000:
minimum_k0 = 24;
break;
case 22050:
minimum_k0 = 17;
break;
case 24000:
minimum_k0 = 16;
break;
case 32000:
minimum_k0 = 16;
break;
case 44100:
minimum_k0 = 12;
break;
case 48000:
minimum_k0 = 11;
break;
case 64000:
minimum_k0 = 10;
break;
case 88200:
minimum_k0 = 7;
break;
case 96000:
minimum_k0 = 7;
break;
default:
minimum_k0 = 11; /* illegal fs */
}
switch (fs) {
case 16000: {
return (minimum_k0 + vector_offset_16k[start_freq]);
} break;
case 22050: {
return (minimum_k0 + vector_offset_22k[start_freq]);
} break;
case 24000: {
return (minimum_k0 + vector_offset_24k[start_freq]);
} break;
case 32000: {
return (minimum_k0 + vector_offset_32k[start_freq]);
} break;
case 44100:
case 48000:
case 64000: {
return (minimum_k0 + vector_offset_44_48_64[start_freq]);
} break;
case 88200:
case 96000: {
return (minimum_k0 + vector_offset_88_96[start_freq]);
} break;
default: {
return (minimum_k0 + vector_offset_def[start_freq]);
}
}
}
static WORD32 ixheaace_get_stop_freq(WORD32 fs, WORD32 stop_freq) {
WORD32 result, i;
WORD32 *v_stop_freq = 0;
WORD32 k1_min;
WORD32 v_dstop[13];
switch (fs) {
case 16000:
k1_min = ixheaace_stop_freq_16k[0];
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_16k[0];
break;
case 22050:
k1_min = ixheaace_stop_freq_22k[0];
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_22k[0];
break;
case 24000:
k1_min = ixheaace_stop_freq_24k[0];
v_stop_freq = (WORD32 *)&ixheaace_stop_freq_24k[0];
break;
case 32000:
k1_min = 32;
v_stop_freq = (WORD32 *)vector_stop_freq_32;
break;
case 44100:
k1_min = 23;
v_stop_freq = (WORD32 *)vector_stop_freq_44;
break;
case 48000:
k1_min = 21;
v_stop_freq = (WORD32 *)vector_stop_freq_48;
break;
default:
v_stop_freq = (WORD32 *)vector_stop_freq_32;
k1_min = 21; /* illegal fs */
}
for (i = 0; i <= 12; i++) {
v_dstop[i] = v_stop_freq[i + 1] - v_stop_freq[i];
}
ixheaace_shellsort_int(v_dstop, 13);
result = k1_min;
for (i = 0; i < stop_freq; i++) {
result = result + v_dstop[i];
}
return result;
}
static WORD32 ixheaace_get_usac_stop_freq(WORD32 fs, WORD32 stop_freq)
{
WORD32 result, i;
WORD32 *v_stop_freq = 0;
WORD32 k1_min;
WORD32 v_dstop[13];
switch (fs)
{
case 16000:
k1_min = ixheaace_usac_stop_freq_16k[0];
v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_16k[0];
break;
case 22050:
k1_min = ixheaace_usac_stop_freq_22k[0];
v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_22k[0];
break;
case 24000:
k1_min = ixheaace_usac_stop_freq_24k[0];
v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_24k[0];
break;
case 32000:
k1_min = 32;
v_stop_freq = (WORD32 *)vector_stop_freq_32;
break;
case 44100:
k1_min = 23;
v_stop_freq = (WORD32 *)vector_stop_freq_44;
break;
case 48000:
k1_min = 21;
v_stop_freq = (WORD32 *)vector_stop_freq_48;
break;
default:
v_stop_freq = (WORD32 *)vector_stop_freq_32;
k1_min = 21; /* illegal fs */
}
for (i = 0; i <= 12; i++)
{
v_dstop[i] = v_stop_freq[i + 1] - v_stop_freq[i];
}
ixheaace_shellsort_int(v_dstop, 13);
result = k1_min;
for (i = 0; i < stop_freq; i++)
{
result = result + v_dstop[i];
}
return result;
}
WORD32
ixheaace_get_sbr_start_freq_raw(WORD32 start_freq, WORD32 qmf_bands, WORD32 fs) {
WORD32 result;
if (start_freq < 0 || start_freq > 15) {
return -1;
}
result = ixheaace_get_start_freq(fs, start_freq);
result = (result * fs / qmf_bands + 1) >> 1;
return result;
}
static WORD32 ixheaace_number_of_bands(WORD32 b_p_o, WORD32 start, WORD32 stop,
FLOAT32 warp_fac) {
WORD32 result = 0;
result = (WORD32)(b_p_o * log((FLOAT32)(stop) / start) / (2.0 * log(2.0) * warp_fac) + 0.5);
result <<= 1;
return result;
}
static VOID ixheaace_calc_bands(WORD32 *ptr_diff, WORD32 start, WORD32 stop, WORD32 num_bands) {
WORD32 i;
WORD32 previous;
WORD32 current;
previous = start;
for (i = 1; i <= num_bands; i++) {
current = (WORD32)((start * pow((FLOAT32)stop / start, (FLOAT32)i / num_bands)) + 0.5f);
ptr_diff[i - 1] = current - previous;
previous = current;
}
}
static VOID ixheaace_modify_bands(WORD32 max_band_previous, WORD32 *ptr_diff, WORD32 length) {
WORD32 change = max_band_previous - ptr_diff[0];
if (change > (ptr_diff[length - 1] - ptr_diff[0]) / 2) {
change = (ptr_diff[length - 1] - ptr_diff[0]) / 2;
}
ptr_diff[0] += change;
ptr_diff[length - 1] -= change;
ixheaace_shellsort_int(ptr_diff, length);
}
static VOID ixheaace_cum_sum(WORD32 start_value, WORD32 *ptr_diff, WORD32 length,
UWORD8 *ptr_start_adress) {
WORD32 i;
ptr_start_adress[0] = (UWORD8)start_value;
for (i = 1; i <= length; i++) {
ptr_start_adress[i] = ptr_start_adress[i - 1] + (UWORD8)ptr_diff[i - 1];
}
}
IA_ERRORCODE
ixheaace_find_start_and_stop_band(const WORD32 sampling_freq, const WORD32 num_channels,
const WORD32 start_freq, const WORD32 stop_freq,
const ixheaace_sr_mode sample_rate_mode, WORD32 *ptr_k0,
WORD32 *ptr_k2, WORD32 sbr_ratio_idx,
ixheaace_sbr_codec_type sbr_codec) {
switch (sbr_codec) {
case USAC_SBR: {
if (sbr_ratio_idx == USAC_SBR_RATIO_INDEX_4_1) {
*ptr_k0 = ixheaace_get_start_freq_4_1(sampling_freq, start_freq);
} else {
*ptr_k0 = ixheaace_get_start_freq(sampling_freq, start_freq);
}
break;
}
default: {
*ptr_k0 = ixheaace_get_start_freq(sampling_freq, start_freq);
break;
}
}
if ((sample_rate_mode == 1) && (sampling_freq * num_channels < 2 * *ptr_k0 * sampling_freq)) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_SAMPLERATE_MODE;
}
if (stop_freq < 14) {
switch (sbr_codec) {
case USAC_SBR: {
if (USAC_SBR_RATIO_INDEX_4_1 == sbr_ratio_idx) {
*ptr_k2 = ixheaace_get_stop_freq_4_1(sampling_freq, stop_freq);
} else {
*ptr_k2 = ixheaace_get_usac_stop_freq(sampling_freq, stop_freq);
}
break;
}
default: {
*ptr_k2 = ixheaace_get_stop_freq(sampling_freq, stop_freq);
break;
}
}
}
else {
*ptr_k2 = (stop_freq == 14 ? 2 * *ptr_k0 : 3 * *ptr_k0);
}
if (*ptr_k2 > num_channels) {
*ptr_k2 = num_channels;
}
if (sbr_codec == USAC_SBR) {
if (sbr_ratio_idx == USAC_SBR_RATIO_INDEX_4_1) {
if (((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_USAC) || (*ptr_k2 <= *ptr_k0)) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
if ((2 * sampling_freq == 44100) && ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_USAC)) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
if ((2 * sampling_freq >= 48000) && ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_USAC)) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else {
if (sampling_freq <= 32000) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_LE32KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else if (sampling_freq == 44100) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_EQ44KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else if (sampling_freq >= 48000) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_GE48KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
}
} else {
if (sampling_freq <= 32000) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_LE32KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else if (sampling_freq == 44100) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_EQ44KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else if (sampling_freq >= 48000) {
if ((*ptr_k2 - *ptr_k0) > MAXIMUM_FREQ_COEFFS_GE48KHZ) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
} else {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
}
if ((*ptr_k2 - *ptr_k0) < 0) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_FREQ_COEFFS;
}
return IA_NO_ERROR;
}
IA_ERRORCODE
ixheaace_update_freq_scale(UWORD8 *ptr_k_master, WORD32 *ptr_num_bands, const WORD32 k0,
const WORD32 k2, const WORD32 freq_scale, const WORD32 alter_scale,
ixheaace_sr_mode sbr_rate)
{
IA_ERRORCODE err_code = IA_NO_ERROR;
WORD32 b_p_o = 0;
WORD32 dk = 0;
FLOAT32 warp;
WORD32 k1 = 0, i;
WORD32 num_bands0;
WORD32 num_bands1;
WORD32 diff_tot[IXHEAACE_MAXIMUM_OCTAVE + IXHEAACE_MAXIMUM_SECOND_REGION] = {0};
WORD32 *diff0 = diff_tot;
WORD32 *diff1 = diff_tot + IXHEAACE_MAXIMUM_OCTAVE;
WORD32 k2_achived;
WORD32 k2_diff;
WORD32 incr = 0;
switch (freq_scale) {
case 1:
b_p_o = 12;
break;
case 2:
b_p_o = 10;
break;
case 3:
b_p_o = 8;
break;
}
if (freq_scale > 0) {
if (alter_scale == 0) {
warp = 1.0f;
} else {
warp = 1.3f;
}
if (IXHEAACE_QUAD_RATE == sbr_rate) {
if (k0 < b_p_o) {
b_p_o = (k0 >> 1) * 2;
}
}
if (4 * k2 >= 9 * k0) {
k1 = 2 * k0;
num_bands0 = ixheaace_number_of_bands(b_p_o, k0, k1, 1.0f);
num_bands1 = ixheaace_number_of_bands(b_p_o, k1, k2, warp);
ixheaace_calc_bands(diff0, k0, k1, num_bands0);
ixheaace_shellsort_int(diff0, num_bands0);
if (diff0[0] == 0) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_NUM_BANDS;
}
ixheaace_cum_sum(k0, diff0, num_bands0, ptr_k_master);
ixheaace_calc_bands(diff1, k1, k2, num_bands1);
ixheaace_shellsort_int(diff1, num_bands1);
if (diff0[num_bands0 - 1] > diff1[0]) {
ixheaace_modify_bands(diff0[num_bands0 - 1], diff1, num_bands1);
}
ixheaace_cum_sum(k1, diff1, num_bands1, &ptr_k_master[num_bands0]);
*ptr_num_bands = num_bands0 + num_bands1;
} else {
k1 = k2;
num_bands0 = ixheaace_number_of_bands(b_p_o, k0, k1, 1.0f);
ixheaace_calc_bands(diff0, k0, k1, num_bands0);
ixheaace_shellsort_int(diff0, num_bands0);
if (diff0[0] == 0) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_NUM_BANDS;
}
ixheaace_cum_sum(k0, diff0, num_bands0, ptr_k_master);
*ptr_num_bands = num_bands0;
}
} else {
if (alter_scale == 0) {
dk = 1;
num_bands0 = 2 * ((k2 - k0) / 2);
} else {
dk = 2;
num_bands0 = 2 * (((k2 - k0) / dk + 1) / 2);
}
k2_achived = k0 + num_bands0 * dk;
k2_diff = k2 - k2_achived;
for (i = 0; i < num_bands0; i++) {
diff_tot[i] = dk;
}
if (k2_diff < 0) {
incr = 1;
i = 0;
}
if (k2_diff > 0) {
incr = -1;
i = num_bands0 - 1;
}
while (k2_diff != 0) {
if (i < 0) break;
diff_tot[i] = diff_tot[i] - incr;
i = i + incr;
k2_diff = k2_diff + incr;
}
ixheaace_cum_sum(k0, diff_tot, num_bands0, ptr_k_master);
*ptr_num_bands = num_bands0;
}
if (*ptr_num_bands < 1) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_NUM_BANDS;
}
if (sbr_rate == IXHEAACE_QUAD_RATE) {
for (i = 1; i < *ptr_num_bands; i++) {
if (!(ptr_k_master[i] - ptr_k_master[i - 1] <= k0 - 2)) {
return IA_EXHEAACE_INIT_FATAL_SBR_INVALID_NUM_BANDS;
}
}
}
return err_code;
}
VOID ixheaace_update_high_res(UWORD8 *ptr_hires, WORD32 *ptr_num_hires, UWORD8 *ptr_k_master,
WORD32 num_master, WORD32 *ptr_xover_band,
ixheaace_sr_mode dr_or_sr, WORD32 num_qmf_ch) {
WORD32 i;
WORD32 divider;
WORD32 max1, max2;
divider = (dr_or_sr == IXHEAACE_DUAL_RATE) ? 2 : 1;
if (dr_or_sr == IXHEAACE_QUAD_RATE) {
divider = 4;
}
if ((ptr_k_master[*ptr_xover_band] > (num_qmf_ch / divider)) ||
(*ptr_xover_band > num_master)) {
max1 = 0;
max2 = num_master;
while ((ptr_k_master[max1 + 1] < (num_qmf_ch / divider)) && ((max1 + 1) < max2)) {
max1++;
}
*ptr_xover_band = max1;
}
*ptr_num_hires = num_master - *ptr_xover_band;
for (i = *ptr_xover_band; i <= num_master; i++) {
ptr_hires[i - *ptr_xover_band] = ptr_k_master[i];
}
}
VOID ixheaace_update_low_res(UWORD8 *ptr_lores, WORD32 *ptr_num_lores, UWORD8 *ptr_hires,
WORD32 ptr_num_hires) {
WORD32 i;
if (ptr_num_hires % 2 == 0) {
*ptr_num_lores = ptr_num_hires / 2;
for (i = 0; i <= *ptr_num_lores; i++) {
ptr_lores[i] = ptr_hires[i * 2];
}
} else {
*ptr_num_lores = (ptr_num_hires + 1) / 2;
ptr_lores[0] = ptr_hires[0];
for (i = 1; i <= *ptr_num_lores; i++) {
ptr_lores[i] = ptr_hires[i * 2 - 1];
}
}
}