916 lines
34 KiB
C
916 lines
34 KiB
C
/******************************************************************************
|
|
*
|
|
* Copyright (C) 2018 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 <stdio.h>
|
|
#include <math.h>
|
|
|
|
#include "impd_type_def.h"
|
|
#include "impd_drc_extr_delta_coded_info.h"
|
|
#include "impd_drc_common.h"
|
|
#include "impd_drc_struct.h"
|
|
#include "impd_drc_interface.h"
|
|
#include "impd_drc_selection_process.h"
|
|
#include "impd_drc_filter_bank.h"
|
|
#include "impd_drc_rom.h"
|
|
VOID impd_signal_peak_level_info(
|
|
ia_drc_config* pstr_drc_config,
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
ia_drc_instructions_struct* str_drc_instruction_str,
|
|
WORD32 requested_dwnmix_id, WORD32 album_mode,
|
|
WORD32 num_compression_eq_count, WORD32* num_compression_eq_id,
|
|
WORD32* peak_info_count, WORD32 eq_set_id[], FLOAT32 signal_peak_level[],
|
|
WORD32 explicit_peak_information_present[]) {
|
|
WORD32 c, d, i, k, n, base_channel_count, mode;
|
|
WORD32 pre_lim_count;
|
|
WORD32 peak_count = 0;
|
|
WORD32 loudness_info_count = 0;
|
|
ia_loudness_info_struct* loudness_info;
|
|
FLOAT32 sum, max_sum;
|
|
WORD32 drc_set_id_requested = str_drc_instruction_str->drc_set_id;
|
|
WORD32 loudness_drc_set_id_requested;
|
|
WORD32 match_found_flag = 0;
|
|
|
|
FLOAT32 signal_peak_level_tmp;
|
|
eq_set_id[0] = 0;
|
|
signal_peak_level[0] = 0.0f;
|
|
explicit_peak_information_present[0] = 0;
|
|
|
|
k = 0;
|
|
if (drc_set_id_requested < 0) {
|
|
for (k = 0; k < num_compression_eq_count; k++) {
|
|
eq_set_id[k] = num_compression_eq_id[k];
|
|
signal_peak_level[k] = 0.0f;
|
|
explicit_peak_information_present[k] = 0;
|
|
}
|
|
}
|
|
eq_set_id[k] = 0;
|
|
signal_peak_level[k] = 0.0f;
|
|
explicit_peak_information_present[k] = 0;
|
|
k++;
|
|
|
|
pre_lim_count = k;
|
|
|
|
if (drc_set_id_requested < 0) {
|
|
loudness_drc_set_id_requested = 0;
|
|
} else {
|
|
loudness_drc_set_id_requested = drc_set_id_requested;
|
|
}
|
|
|
|
if (album_mode == 1) {
|
|
mode = 1;
|
|
loudness_info_count = pstr_loudness_info->loudness_info_album_count;
|
|
} else {
|
|
mode = 0;
|
|
loudness_info_count = pstr_loudness_info->loudness_info_count;
|
|
}
|
|
|
|
for (n = 0; n < loudness_info_count; n++) {
|
|
if (mode == 1) {
|
|
loudness_info = &(pstr_loudness_info->str_loudness_info_album[n]);
|
|
} else {
|
|
loudness_info = &(pstr_loudness_info->loudness_info[n]);
|
|
}
|
|
if (loudness_drc_set_id_requested == loudness_info->drc_set_id &&
|
|
requested_dwnmix_id == loudness_info->downmix_id) {
|
|
if (loudness_info->true_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] = loudness_info->true_peak_level;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
if (match_found_flag == 0) {
|
|
if (loudness_info->sample_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] = loudness_info->sample_peak_level;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
for (n = 0; n < loudness_info_count; n++) {
|
|
if (mode == 1) {
|
|
loudness_info = &(pstr_loudness_info->str_loudness_info_album[n]);
|
|
} else {
|
|
loudness_info = &(pstr_loudness_info->loudness_info[n]);
|
|
}
|
|
if (ID_FOR_ANY_DRC == loudness_info->drc_set_id &&
|
|
requested_dwnmix_id == loudness_info->downmix_id) {
|
|
if (loudness_info->true_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] = loudness_info->true_peak_level;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
if (match_found_flag == 0) {
|
|
if (loudness_info->sample_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] = loudness_info->sample_peak_level;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
for (i = 0; i < str_drc_instruction_str->dwnmix_id_count; i++) {
|
|
if (requested_dwnmix_id == str_drc_instruction_str->downmix_id[0] ||
|
|
ID_FOR_ANY_DOWNMIX == str_drc_instruction_str->downmix_id[0]) {
|
|
if (str_drc_instruction_str->limiter_peak_target_present) {
|
|
if (str_drc_instruction_str->requires_eq == 1) {
|
|
for (d = 0;
|
|
d < pstr_drc_config->str_drc_config_ext.eq_instructions_count;
|
|
d++) {
|
|
ia_eq_instructions_struct* eq_instructions =
|
|
&pstr_drc_config->str_drc_config_ext.str_eq_instructions[d];
|
|
for (c = 0; c < eq_instructions->drc_set_id_count; c++) {
|
|
if ((eq_instructions->drc_set_id[c] ==
|
|
loudness_drc_set_id_requested) ||
|
|
(eq_instructions->drc_set_id[c] == ID_FOR_ANY_DRC)) {
|
|
for (i = 0; i < eq_instructions->dwnmix_id_count; i++) {
|
|
if ((eq_instructions->downmix_id[i] ==
|
|
requested_dwnmix_id) ||
|
|
(eq_instructions->downmix_id[i] ==
|
|
ID_FOR_ANY_DOWNMIX)) {
|
|
eq_set_id[peak_count] = eq_instructions->eq_set_id;
|
|
signal_peak_level[peak_count] =
|
|
str_drc_instruction_str->limiter_peak_target;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else
|
|
|
|
{
|
|
eq_set_id[peak_count] = 0;
|
|
signal_peak_level[peak_count] =
|
|
str_drc_instruction_str->limiter_peak_target;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
for (i = 1; i < str_drc_instruction_str->dwnmix_id_count; i++) {
|
|
if (requested_dwnmix_id == str_drc_instruction_str->downmix_id[i]) {
|
|
if (str_drc_instruction_str->limiter_peak_target_present) {
|
|
{
|
|
eq_set_id[peak_count] = 0;
|
|
signal_peak_level[peak_count] =
|
|
str_drc_instruction_str->limiter_peak_target;
|
|
explicit_peak_information_present[peak_count] = 1;
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
if (requested_dwnmix_id != ID_FOR_BASE_LAYOUT) {
|
|
signal_peak_level_tmp = 0.f;
|
|
for (i = 0; i < pstr_drc_config->dwnmix_instructions_count; i++) {
|
|
if (pstr_drc_config->dwnmix_instructions[i].downmix_id ==
|
|
requested_dwnmix_id) {
|
|
if (pstr_drc_config->dwnmix_instructions[i]
|
|
.downmix_coefficients_present) {
|
|
base_channel_count =
|
|
pstr_drc_config->channel_layout.base_channel_count;
|
|
max_sum = 0.0f;
|
|
for (c = 0;
|
|
c <
|
|
pstr_drc_config->dwnmix_instructions[i].target_channel_count;
|
|
c++) {
|
|
sum = 0.0f;
|
|
for (d = 0; d < base_channel_count; d++) {
|
|
sum += pstr_drc_config->dwnmix_instructions[i]
|
|
.downmix_coefficient[c * base_channel_count + d];
|
|
}
|
|
if (max_sum < sum) max_sum = sum;
|
|
}
|
|
signal_peak_level_tmp = 20.0f * (FLOAT32)log10(max_sum);
|
|
} else {
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
for (n = 0; n < loudness_info_count; n++) {
|
|
if (mode == 1) {
|
|
loudness_info = &(pstr_loudness_info->str_loudness_info_album[n]);
|
|
} else {
|
|
loudness_info = &(pstr_loudness_info->loudness_info[n]);
|
|
}
|
|
if (loudness_drc_set_id_requested == loudness_info->drc_set_id &&
|
|
ID_FOR_BASE_LAYOUT == loudness_info->downmix_id) {
|
|
if (loudness_info->true_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] =
|
|
loudness_info->true_peak_level + signal_peak_level_tmp;
|
|
explicit_peak_information_present[peak_count] = 0;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
if (match_found_flag == 0) {
|
|
if (loudness_info->sample_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] =
|
|
loudness_info->sample_peak_level + signal_peak_level_tmp;
|
|
explicit_peak_information_present[peak_count] = 0;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
for (n = 0; n < loudness_info_count; n++) {
|
|
if (mode == 1) {
|
|
loudness_info = &(pstr_loudness_info->str_loudness_info_album[n]);
|
|
} else {
|
|
loudness_info = &(pstr_loudness_info->loudness_info[n]);
|
|
}
|
|
if (ID_FOR_ANY_DRC == loudness_info->drc_set_id &&
|
|
ID_FOR_BASE_LAYOUT == loudness_info->downmix_id) {
|
|
if (loudness_info->true_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] =
|
|
loudness_info->true_peak_level + signal_peak_level_tmp;
|
|
explicit_peak_information_present[peak_count] = 0;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
if (match_found_flag == 0) {
|
|
if (loudness_info->sample_peak_level_present) {
|
|
eq_set_id[peak_count] = loudness_info->eq_set_id;
|
|
|
|
signal_peak_level[peak_count] =
|
|
loudness_info->sample_peak_level + signal_peak_level_tmp;
|
|
explicit_peak_information_present[peak_count] = 0;
|
|
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (match_found_flag == 0) {
|
|
ia_drc_instructions_struct* drc_instructions_drc_tmp;
|
|
for (n = 0; n < pstr_drc_config->drc_instructions_count_plus; n++) {
|
|
drc_instructions_drc_tmp =
|
|
&pstr_drc_config->str_drc_instruction_str[n];
|
|
if (loudness_drc_set_id_requested ==
|
|
drc_instructions_drc_tmp->drc_set_id) {
|
|
if (ID_FOR_BASE_LAYOUT == drc_instructions_drc_tmp->downmix_id[0]) {
|
|
if (drc_instructions_drc_tmp->limiter_peak_target_present) {
|
|
eq_set_id[peak_count] = -1;
|
|
signal_peak_level[peak_count] =
|
|
drc_instructions_drc_tmp->limiter_peak_target +
|
|
signal_peak_level_tmp;
|
|
explicit_peak_information_present[peak_count] = 0;
|
|
match_found_flag = 1;
|
|
peak_count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (peak_count > 0) {
|
|
*peak_info_count = peak_count;
|
|
} else {
|
|
*peak_info_count = pre_lim_count;
|
|
}
|
|
return;
|
|
}
|
|
|
|
WORD32
|
|
impd_extract_loudness_peak_to_average_info(
|
|
ia_loudness_info_struct* loudness_info, WORD32 dyn_range_measurement_type,
|
|
WORD32* loudness_peak_2_avg_value_present,
|
|
FLOAT32* loudness_peak_2_avg_value) {
|
|
WORD32 k;
|
|
WORD32 program_loudness_present = 0;
|
|
WORD32 peak_loudness_present = 0;
|
|
WORD32 match_measure_program_loudness = 0;
|
|
WORD32 match_measure_peak_loudness = 0;
|
|
FLOAT32 program_loudness = 0.0f;
|
|
FLOAT32 peak_loudness = 0.0f;
|
|
ia_loudness_measure_struct* loudness_measure = NULL;
|
|
|
|
for (k = 0; k < loudness_info->measurement_count; k++) {
|
|
loudness_measure = &(loudness_info->loudness_measure[k]);
|
|
if (loudness_measure->method_def == METHOD_DEFINITION_PROGRAM_LOUDNESS) {
|
|
if (match_measure_program_loudness <
|
|
measurement_method_prog_loudness_tbl[loudness_measure
|
|
->measurement_system]) {
|
|
program_loudness = loudness_measure->method_val;
|
|
program_loudness_present = 1;
|
|
match_measure_program_loudness =
|
|
measurement_method_prog_loudness_tbl[loudness_measure
|
|
->measurement_system];
|
|
}
|
|
}
|
|
switch (dyn_range_measurement_type) {
|
|
case SHORT_TERM_LOUDNESS_TO_AVG:
|
|
if (loudness_measure->method_def ==
|
|
METHOD_DEFINITION_SHORT_TERM_LOUDNESS_MAX) {
|
|
if (match_measure_peak_loudness <
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system]) {
|
|
peak_loudness = loudness_measure->method_val;
|
|
peak_loudness_present = 1;
|
|
match_measure_peak_loudness =
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MOMENTARY_LOUDNESS_TO_AVG:
|
|
if (loudness_measure->method_def ==
|
|
METHOD_DEFINITION_MOMENTARY_LOUDNESS_MAX) {
|
|
if (match_measure_peak_loudness <
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system]) {
|
|
peak_loudness = loudness_measure->method_val;
|
|
peak_loudness_present = 1;
|
|
match_measure_peak_loudness =
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system];
|
|
}
|
|
}
|
|
break;
|
|
|
|
case TOP_OF_LOUDNESS_RANGE_TO_AVG:
|
|
if (loudness_measure->method_def ==
|
|
METHOD_DEFINITION_MAX_OF_LOUDNESS_RANGE) {
|
|
if (match_measure_peak_loudness <
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system]) {
|
|
peak_loudness = loudness_measure->method_val;
|
|
peak_loudness_present = 1;
|
|
match_measure_peak_loudness =
|
|
measurement_method_peak_loudness_tbl[loudness_measure
|
|
->measurement_system];
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return (UNEXPECTED_ERROR);
|
|
|
|
break;
|
|
}
|
|
}
|
|
if ((program_loudness_present == 1) && (peak_loudness_present == 1)) {
|
|
*loudness_peak_2_avg_value = peak_loudness - program_loudness;
|
|
*loudness_peak_2_avg_value_present = 1;
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
WORD32 impd_loudness_peak_to_average_info(
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
ia_drc_instructions_struct* str_drc_instruction_str,
|
|
WORD32 requested_dwnmix_id, WORD32 dyn_range_measurement_type,
|
|
WORD32 album_mode, WORD32* loudness_peak_2_avg_value_present,
|
|
FLOAT32* loudness_peak_2_avg_value) {
|
|
WORD32 n, err;
|
|
WORD32 drc_set_id = max(0, str_drc_instruction_str->drc_set_id);
|
|
|
|
*loudness_peak_2_avg_value_present = 0;
|
|
|
|
if (album_mode == 1) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_album_count; n++) {
|
|
ia_loudness_info_struct* loudness_info =
|
|
&(pstr_loudness_info->str_loudness_info_album[n]);
|
|
if (drc_set_id == loudness_info->drc_set_id) {
|
|
if (requested_dwnmix_id == loudness_info->downmix_id) {
|
|
err = impd_extract_loudness_peak_to_average_info(
|
|
loudness_info, dyn_range_measurement_type,
|
|
loudness_peak_2_avg_value_present, loudness_peak_2_avg_value);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*loudness_peak_2_avg_value_present == 0) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_count; n++) {
|
|
ia_loudness_info_struct* loudness_info =
|
|
&(pstr_loudness_info->loudness_info[n]);
|
|
if (drc_set_id == loudness_info->drc_set_id) {
|
|
if (requested_dwnmix_id == loudness_info->downmix_id) {
|
|
err = impd_extract_loudness_peak_to_average_info(
|
|
loudness_info, dyn_range_measurement_type,
|
|
loudness_peak_2_avg_value_present, loudness_peak_2_avg_value);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
VOID impd_overall_loudness_present(ia_loudness_info_struct* loudness_info,
|
|
WORD32* loudness_info_present) {
|
|
WORD32 m;
|
|
|
|
*loudness_info_present = 0;
|
|
for (m = 0; m < loudness_info->measurement_count; m++) {
|
|
if ((loudness_info->loudness_measure[m].method_def ==
|
|
METHOD_DEFINITION_PROGRAM_LOUDNESS) ||
|
|
(loudness_info->loudness_measure[m].method_def ==
|
|
METHOD_DEFINITION_ANCHOR_LOUDNESS)) {
|
|
*loudness_info_present = 1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
WORD32 impd_check_loud_info(WORD32 loudness_info_count,
|
|
ia_loudness_info_struct* loudness_info,
|
|
WORD32 requested_dwnmix_id,
|
|
WORD32 drc_set_id_requested, WORD32* info_count,
|
|
ia_loudness_info_struct* loudness_info_matching[]) {
|
|
WORD32 n;
|
|
WORD32 loudness_info_present;
|
|
for (n = 0; n < loudness_info_count; n++) {
|
|
if (requested_dwnmix_id == loudness_info[n].downmix_id) {
|
|
if (drc_set_id_requested == loudness_info[n].drc_set_id) {
|
|
impd_overall_loudness_present(&(loudness_info[n]),
|
|
&loudness_info_present);
|
|
|
|
if (loudness_info_present) {
|
|
loudness_info_matching[*info_count] = &(loudness_info[n]);
|
|
(*info_count)++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
WORD32 impd_check_loud_payload(
|
|
WORD32 loudness_info_count, ia_loudness_info_struct* loudness_info,
|
|
WORD32 requested_dwnmix_id, WORD32 drc_set_id_requested, WORD32* info_count,
|
|
ia_loudness_info_struct* loudness_info_matching[]) {
|
|
WORD32 err = 0;
|
|
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
requested_dwnmix_id, drc_set_id_requested,
|
|
info_count, loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_ANY_DOWNMIX, drc_set_id_requested,
|
|
info_count, loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
requested_dwnmix_id, ID_FOR_ANY_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
requested_dwnmix_id, ID_FOR_NO_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_ANY_DOWNMIX, ID_FOR_ANY_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_ANY_DOWNMIX, ID_FOR_NO_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_BASE_LAYOUT, drc_set_id_requested,
|
|
info_count, loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_BASE_LAYOUT, ID_FOR_ANY_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
err = impd_check_loud_info(loudness_info_count, loudness_info,
|
|
ID_FOR_BASE_LAYOUT, ID_FOR_NO_DRC, info_count,
|
|
loudness_info_matching);
|
|
if (err || *info_count) goto matchEnd;
|
|
matchEnd:
|
|
return (err);
|
|
}
|
|
|
|
WORD32 impd_find_overall_loudness_info(
|
|
ia_drc_sel_proc_params_struct* pstr_drc_sel_proc_params_struct,
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
WORD32 requested_dwnmix_id, WORD32 drc_set_id_requested,
|
|
WORD32* overall_loudness_info_present, WORD32* info_count,
|
|
ia_loudness_info_struct* loudness_info_matching[]) {
|
|
WORD32 err;
|
|
WORD32 loudness_drc_set_id_requested;
|
|
|
|
*info_count = 0;
|
|
if (drc_set_id_requested < 0) {
|
|
loudness_drc_set_id_requested = ID_FOR_NO_DRC;
|
|
} else {
|
|
loudness_drc_set_id_requested = drc_set_id_requested;
|
|
}
|
|
if (pstr_drc_sel_proc_params_struct->album_mode == 1) {
|
|
err = impd_check_loud_payload(
|
|
pstr_loudness_info->loudness_info_album_count,
|
|
pstr_loudness_info->str_loudness_info_album, requested_dwnmix_id,
|
|
loudness_drc_set_id_requested, info_count, loudness_info_matching);
|
|
if (err) return (err);
|
|
}
|
|
if (*info_count == 0) {
|
|
err = impd_check_loud_payload(pstr_loudness_info->loudness_info_count,
|
|
pstr_loudness_info->loudness_info,
|
|
requested_dwnmix_id,
|
|
loudness_drc_set_id_requested,
|
|
|
|
info_count, loudness_info_matching);
|
|
if (err) return (err);
|
|
}
|
|
*overall_loudness_info_present = (*info_count > 0);
|
|
return (0);
|
|
}
|
|
|
|
WORD32
|
|
impd_high_pass_loudness_adjust_info(ia_loudness_info_struct* loudness_info,
|
|
WORD32* loudness_hp_adjust_present,
|
|
FLOAT32* loudness_hp_adjust) {
|
|
WORD32 m, k;
|
|
|
|
*loudness_hp_adjust_present = 0;
|
|
*loudness_hp_adjust = 0.0f;
|
|
for (m = 0; m < loudness_info->measurement_count; m++) {
|
|
if (loudness_info->loudness_measure[m].measurement_system ==
|
|
MEASUREMENT_SYSTEM_BS_1770_4_PRE_PROCESSING) {
|
|
for (k = 0; k < loudness_info->measurement_count; k++) {
|
|
if (loudness_info->loudness_measure[k].measurement_system ==
|
|
MEASUREMENT_SYSTEM_BS_1770_4) {
|
|
if (loudness_info->loudness_measure[m].method_def ==
|
|
loudness_info->loudness_measure[k].method_def) {
|
|
*loudness_hp_adjust_present = 1;
|
|
*loudness_hp_adjust =
|
|
loudness_info->loudness_measure[m].method_val -
|
|
loudness_info->loudness_measure[k].method_val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
WORD32 impd_find_high_pass_loudness_adjust(
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
WORD32 requested_dwnmix_id, WORD32 drc_set_id_requested, WORD32 album_mode,
|
|
FLOAT32 device_cutoff_freq, WORD32* loudness_hp_adjust_present,
|
|
FLOAT32* loudness_hp_adjust) {
|
|
WORD32 n, err;
|
|
WORD32 loudness_drc_set_id_requested;
|
|
|
|
if (drc_set_id_requested < 0) {
|
|
loudness_drc_set_id_requested = 0;
|
|
} else {
|
|
loudness_drc_set_id_requested = drc_set_id_requested;
|
|
}
|
|
|
|
*loudness_hp_adjust_present = 0;
|
|
|
|
if (album_mode == 1) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_album_count; n++) {
|
|
if ((requested_dwnmix_id ==
|
|
pstr_loudness_info->str_loudness_info_album[n].downmix_id) ||
|
|
(ID_FOR_ANY_DOWNMIX ==
|
|
pstr_loudness_info->str_loudness_info_album[n].downmix_id)) {
|
|
if (loudness_drc_set_id_requested ==
|
|
pstr_loudness_info->str_loudness_info_album[n].drc_set_id) {
|
|
err = impd_high_pass_loudness_adjust_info(
|
|
&(pstr_loudness_info->loudness_info[n]),
|
|
loudness_hp_adjust_present, loudness_hp_adjust);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*loudness_hp_adjust_present == 0) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_count; n++) {
|
|
if ((requested_dwnmix_id ==
|
|
pstr_loudness_info->loudness_info[n].downmix_id) ||
|
|
(ID_FOR_ANY_DOWNMIX ==
|
|
pstr_loudness_info->loudness_info[n].downmix_id)) {
|
|
if (loudness_drc_set_id_requested ==
|
|
pstr_loudness_info->loudness_info[n].drc_set_id) {
|
|
err = impd_high_pass_loudness_adjust_info(
|
|
&(pstr_loudness_info->loudness_info[n]),
|
|
loudness_hp_adjust_present, loudness_hp_adjust);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*loudness_hp_adjust_present == 0) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_count; n++) {
|
|
if (ID_FOR_BASE_LAYOUT ==
|
|
pstr_loudness_info->loudness_info[n].downmix_id) /* base layout */
|
|
{
|
|
if (loudness_drc_set_id_requested ==
|
|
pstr_loudness_info->loudness_info[n].drc_set_id) {
|
|
err = impd_high_pass_loudness_adjust_info(
|
|
&(pstr_loudness_info->loudness_info[n]),
|
|
loudness_hp_adjust_present, loudness_hp_adjust);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*loudness_hp_adjust_present == 0) {
|
|
for (n = 0; n < pstr_loudness_info->loudness_info_count; n++) {
|
|
if (ID_FOR_BASE_LAYOUT ==
|
|
pstr_loudness_info->loudness_info[n].downmix_id) /* base layout */
|
|
{
|
|
if (0 == pstr_loudness_info->loudness_info[n].drc_set_id) {
|
|
err = impd_high_pass_loudness_adjust_info(
|
|
&(pstr_loudness_info->loudness_info[n]),
|
|
loudness_hp_adjust_present, loudness_hp_adjust);
|
|
if (err) return (err);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (*loudness_hp_adjust_present == 0) {
|
|
*loudness_hp_adjust = 0.0f;
|
|
} else {
|
|
*loudness_hp_adjust *=
|
|
(max(20.0f, min(500.0f, device_cutoff_freq)) - 20.0f) /
|
|
(500.0f - 20.0f);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
WORD32 impd_init_loudness_control(
|
|
ia_drc_sel_proc_params_struct* pstr_drc_sel_proc_params_struct,
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
WORD32 requested_dwnmix_id, WORD32 drc_set_id_requested,
|
|
WORD32 num_compression_eq_count, WORD32* num_compression_eq_id,
|
|
WORD32* loudness_info_count, WORD32 eq_set_id[],
|
|
FLOAT32 loudness_normalization_gain_db[], FLOAT32 loudness[]) {
|
|
WORD32 err, k, info_count = 0, pre_lim_count;
|
|
WORD32 loudness_hp_adjust_present;
|
|
WORD32 overall_loudness_info_present;
|
|
FLOAT32 pre_proc_adjust;
|
|
|
|
k = 0;
|
|
if (drc_set_id_requested < 0) {
|
|
for (k = 0; k < num_compression_eq_count; k++) {
|
|
eq_set_id[k] = num_compression_eq_id[k];
|
|
loudness[k] = UNDEFINED_LOUDNESS_VALUE;
|
|
loudness_normalization_gain_db[k] = 0.0f;
|
|
}
|
|
}
|
|
if (k >= MAX_NUM_COMPRESSION_EQ) return UNEXPECTED_ERROR;
|
|
eq_set_id[k] = 0;
|
|
|
|
loudness[k] = UNDEFINED_LOUDNESS_VALUE;
|
|
|
|
loudness_normalization_gain_db[k] = 0.0f;
|
|
k++;
|
|
|
|
pre_lim_count = k;
|
|
|
|
if (pstr_drc_sel_proc_params_struct->loudness_normalization_on == 1) {
|
|
WORD32 n;
|
|
ia_loudness_info_struct* loudness_info[16];
|
|
err = impd_find_overall_loudness_info(
|
|
pstr_drc_sel_proc_params_struct, pstr_loudness_info,
|
|
requested_dwnmix_id, drc_set_id_requested,
|
|
&overall_loudness_info_present, &info_count, loudness_info);
|
|
if (err) return (err);
|
|
|
|
if (overall_loudness_info_present == 1) {
|
|
WORD32 requested_method_definition = METHOD_DEFINITION_PROGRAM_LOUDNESS;
|
|
WORD32 other_method_definition = METHOD_DEFINITION_PROGRAM_LOUDNESS;
|
|
WORD32 requested_measurement_system = MEASUREMENT_SYSTEM_BS_1770_4;
|
|
WORD32 requested_preprocessing = 0;
|
|
|
|
const WORD32* system_bonus = measurement_system_default_tbl;
|
|
|
|
WORD32 match_measure;
|
|
FLOAT32 method_val = 0;
|
|
|
|
switch (pstr_drc_sel_proc_params_struct->loudness_measurement_method) {
|
|
case USER_METHOD_DEFINITION_DEFAULT:
|
|
case USER_METHOD_DEFINITION_PROGRAM_LOUDNESS:
|
|
requested_method_definition = METHOD_DEFINITION_PROGRAM_LOUDNESS;
|
|
other_method_definition = METHOD_DEFINITION_ANCHOR_LOUDNESS;
|
|
break;
|
|
case USER_METHOD_DEFINITION_ANCHOR_LOUDNESS:
|
|
requested_method_definition = METHOD_DEFINITION_ANCHOR_LOUDNESS;
|
|
other_method_definition = METHOD_DEFINITION_PROGRAM_LOUDNESS;
|
|
break;
|
|
|
|
default:
|
|
return (UNEXPECTED_ERROR);
|
|
break;
|
|
}
|
|
|
|
switch (pstr_drc_sel_proc_params_struct->loudness_measurement_system) {
|
|
case USER_MEASUREMENT_SYSTEM_DEFAULT:
|
|
case USER_MEASUREMENT_SYSTEM_BS_1770_4:
|
|
requested_measurement_system = MEASUREMENT_SYSTEM_BS_1770_4;
|
|
system_bonus = measurement_system_bs1770_3_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_USER:
|
|
requested_measurement_system = MEASUREMENT_SYSTEM_USER;
|
|
system_bonus = measurement_system_user_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_EXPERT_PANEL:
|
|
requested_measurement_system = MEASUREMENT_SYSTEM_EXPERT_PANEL;
|
|
system_bonus = measurement_system_expert_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_RESERVED_A:
|
|
requested_measurement_system = USER_MEASUREMENT_SYSTEM_RESERVED_A;
|
|
system_bonus = measurement_system_rms_a_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_RESERVED_B:
|
|
requested_measurement_system = USER_MEASUREMENT_SYSTEM_RESERVED_B;
|
|
system_bonus = measurement_system_rms_b_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_RESERVED_C:
|
|
requested_measurement_system = USER_MEASUREMENT_SYSTEM_RESERVED_C;
|
|
system_bonus = measurement_system_rms_c_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_RESERVED_D:
|
|
requested_measurement_system = USER_MEASUREMENT_SYSTEM_RESERVED_D;
|
|
system_bonus = measurement_system_rms_d_tbl;
|
|
break;
|
|
case USER_MEASUREMENT_SYSTEM_RESERVED_E:
|
|
requested_measurement_system = USER_MEASUREMENT_SYSTEM_RESERVED_E;
|
|
system_bonus = measurement_system_rms_e_tbl;
|
|
break;
|
|
|
|
default:
|
|
return (UNEXPECTED_ERROR);
|
|
break;
|
|
}
|
|
|
|
switch (pstr_drc_sel_proc_params_struct->loudness_measurement_pre_proc) {
|
|
case USER_LOUDNESS_PREPROCESSING_DEFAULT:
|
|
case USER_LOUDNESS_PREPROCESSING_OFF:
|
|
requested_preprocessing = 0;
|
|
break;
|
|
case USER_LOUDNESS_PREPROCESSING_HIGHPASS:
|
|
requested_preprocessing = 1;
|
|
break;
|
|
|
|
default:
|
|
return (UNEXPECTED_ERROR);
|
|
break;
|
|
}
|
|
|
|
for (k = 0; k < info_count; k++) {
|
|
match_measure = -1;
|
|
for (n = 0; n < loudness_info[k]->measurement_count; n++) {
|
|
ia_loudness_measure_struct* loudness_measure =
|
|
&(loudness_info[k]->loudness_measure[n]);
|
|
if (match_measure <
|
|
system_bonus[loudness_measure->measurement_system] &&
|
|
requested_method_definition == loudness_measure->method_def) {
|
|
method_val = loudness_measure->method_val;
|
|
match_measure = system_bonus[loudness_measure->measurement_system];
|
|
}
|
|
}
|
|
if (match_measure == -1) {
|
|
for (n = 0; n < loudness_info[k]->measurement_count; n++) {
|
|
ia_loudness_measure_struct* loudness_measure =
|
|
&(loudness_info[k]->loudness_measure[n]);
|
|
if (match_measure <
|
|
system_bonus[loudness_measure->measurement_system] &&
|
|
other_method_definition == loudness_measure->method_def) {
|
|
method_val = loudness_measure->method_val;
|
|
match_measure =
|
|
system_bonus[loudness_measure->measurement_system];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (requested_preprocessing == 1) {
|
|
err = impd_find_high_pass_loudness_adjust(
|
|
pstr_loudness_info, requested_dwnmix_id, drc_set_id_requested,
|
|
pstr_drc_sel_proc_params_struct->album_mode,
|
|
(FLOAT32)
|
|
pstr_drc_sel_proc_params_struct->device_cut_off_frequency,
|
|
&loudness_hp_adjust_present, &pre_proc_adjust);
|
|
if (err) return (err);
|
|
|
|
if (loudness_hp_adjust_present == 0) {
|
|
pre_proc_adjust = -2.0f;
|
|
}
|
|
method_val += pre_proc_adjust;
|
|
}
|
|
|
|
eq_set_id[k] = 0;
|
|
|
|
loudness_normalization_gain_db[k] =
|
|
pstr_drc_sel_proc_params_struct->target_loudness - method_val;
|
|
loudness[k] = method_val;
|
|
}
|
|
}
|
|
}
|
|
if (info_count > 0) {
|
|
*loudness_info_count = info_count;
|
|
} else {
|
|
*loudness_info_count = pre_lim_count;
|
|
}
|
|
|
|
return (0);
|
|
}
|
|
|
|
#define MIXING_LEVEL_DEFAULT 85.0f
|
|
WORD32
|
|
impd_mixing_level_info(
|
|
ia_drc_sel_proc_params_struct* pstr_drc_sel_proc_params_struct,
|
|
ia_drc_loudness_info_set_struct* pstr_loudness_info,
|
|
WORD32 requested_dwnmix_id, WORD32 drc_set_id_requested,
|
|
WORD32 eq_set_id_requested, FLOAT32* mixing_level) {
|
|
WORD32 n, k, info_count;
|
|
WORD32 album_mode = pstr_drc_sel_proc_params_struct->album_mode;
|
|
WORD32 loudness_drc_set_id_requested;
|
|
ia_loudness_info_struct* loudness_info;
|
|
|
|
*mixing_level = MIXING_LEVEL_DEFAULT;
|
|
if (drc_set_id_requested < 0) {
|
|
loudness_drc_set_id_requested = 0;
|
|
} else {
|
|
loudness_drc_set_id_requested = drc_set_id_requested;
|
|
}
|
|
if (album_mode == 1) {
|
|
info_count = pstr_loudness_info->loudness_info_album_count;
|
|
loudness_info = pstr_loudness_info->str_loudness_info_album;
|
|
} else {
|
|
info_count = pstr_loudness_info->loudness_info_count;
|
|
loudness_info = pstr_loudness_info->loudness_info;
|
|
}
|
|
for (n = 0; n < info_count; n++) {
|
|
if ((requested_dwnmix_id == loudness_info[n].downmix_id) ||
|
|
(ID_FOR_ANY_DOWNMIX == loudness_info[n].downmix_id)) {
|
|
if (loudness_drc_set_id_requested == loudness_info[n].drc_set_id) {
|
|
if (eq_set_id_requested == loudness_info[n].eq_set_id) {
|
|
for (k = 0; k < loudness_info[n].measurement_count; k++) {
|
|
if (loudness_info[n].loudness_measure[k].method_def ==
|
|
METHOD_DEFINITION_MIXING_LEVEL) {
|
|
*mixing_level = loudness_info[n].loudness_measure[k].method_val;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return (0);
|
|
}
|