From 71e832fb30c92e36a59f046c365593ce686c4f94 Mon Sep 17 00:00:00 2001 From: aikiriao Date: Sat, 13 Jul 2024 00:41:50 +0900 Subject: [PATCH] improve pre-emphasis filter. --- libs/srla_decoder/src/srla_decoder.c | 5 +- libs/srla_encoder/src/srla_encoder.c | 20 +++-- libs/srla_internal/include/srla_internal.h | 2 +- libs/srla_internal/include/srla_utility.h | 8 +- libs/srla_internal/src/srla_utility.c | 91 ++++++++++++++++------ 5 files changed, 83 insertions(+), 43 deletions(-) diff --git a/libs/srla_decoder/src/srla_decoder.c b/libs/srla_decoder/src/srla_decoder.c index 4dd0d4d..373b549 100644 --- a/libs/srla_decoder/src/srla_decoder.c +++ b/libs/srla_decoder/src/srla_decoder.c @@ -454,9 +454,8 @@ static SRLAApiResult SRLADecoder_DecodeCompressData( } /* プリエンファシス係数 */ for (l = 0; l < SRLA_NUM_PREEMPHASIS_FILTERS; l++) { - /* プリエンファシス係数は正値に制限しているため1bitケチれる */ - BitReader_GetBits(&reader, &uval, SRLA_PREEMPHASIS_COEF_SHIFT - 1); - decoder->de_emphasis[ch][l].coef = (int32_t)uval; + BitReader_GetBits(&reader, &uval, SRLA_PREEMPHASIS_COEF_SHIFT + 1); + decoder->de_emphasis[ch][l].coef = SRLAUTILITY_UINT32_TO_SINT32(uval); } } /* LPC係数次数/LPC係数右シフト量/LPC係数 */ diff --git a/libs/srla_encoder/src/srla_encoder.c b/libs/srla_encoder/src/srla_encoder.c index a357d0b..722e6e0 100644 --- a/libs/srla_encoder/src/srla_encoder.c +++ b/libs/srla_encoder/src/srla_encoder.c @@ -997,13 +997,13 @@ static SRLAError SRLAEncoder_ComputeCoefficientsPerChannel( /* プリエンファシスフィルタ群 */ { const int32_t head = buffer_int[0]; + struct SRLAPreemphasisFilter filter[SRLA_NUM_PREEMPHASIS_FILTERS] = { 0, }; + SRLAPreemphasisFilter_CalculateMultiStageCoefficients(filter, SRLA_NUM_PREEMPHASIS_FILTERS, buffer_int, num_samples); for (p = 0; p < SRLA_NUM_PREEMPHASIS_FILTERS; p++) { - struct SRLAPreemphasisFilter filter = { 0, }; - filter.prev = head; - SRLAPreemphasisFilter_CalculateCoefficient(&filter, buffer_int, num_samples); - SRLAPreemphasisFilter_Preemphasis(&filter, buffer_int, num_samples); + filter[p].prev = head; + SRLAPreemphasisFilter_Preemphasis(&filter[p], buffer_int, num_samples); tmp_pre_emphasis_filters[p].prev = head; - tmp_pre_emphasis_filters[p].coef = filter.coef; + tmp_pre_emphasis_filters[p].coef = filter[p].coef; } } @@ -1070,7 +1070,7 @@ static SRLAError SRLAEncoder_ComputeCoefficientsPerChannel( /* プリエンファシスフィルタのバッファ/係数 */ tmp_code_length += header->bits_per_sample + 1; for (p = 0; p < SRLA_NUM_PREEMPHASIS_FILTERS; p++) { - tmp_code_length += SRLA_PREEMPHASIS_COEF_SHIFT - 1; + tmp_code_length += SRLA_PREEMPHASIS_COEF_SHIFT + 1; } /* LPC係数次数/LPC係数右シフト量 */ @@ -1300,11 +1300,9 @@ static SRLAApiResult SRLAEncoder_EncodeCompressData( SRLA_ASSERT(uval < (1U << (header->bits_per_sample + 1))); BitWriter_PutBits(&writer, uval, header->bits_per_sample + 1); for (p = 0; p < SRLA_NUM_PREEMPHASIS_FILTERS; p++) { - /* プリエンファシス係数は正値に制限しているため1bitケチれる */ - SRLA_ASSERT(encoder->pre_emphasis[ch][p].coef >= 0); - uval = (uint32_t)encoder->pre_emphasis[ch][p].coef; - SRLA_ASSERT(uval < (1U << (SRLA_PREEMPHASIS_COEF_SHIFT - 1))); - BitWriter_PutBits(&writer, uval, SRLA_PREEMPHASIS_COEF_SHIFT - 1); + uval = SRLAUTILITY_SINT32_TO_UINT32(encoder->pre_emphasis[ch][p].coef); + SRLA_ASSERT(uval < (1U << (SRLA_PREEMPHASIS_COEF_SHIFT + 1))); + BitWriter_PutBits(&writer, uval, SRLA_PREEMPHASIS_COEF_SHIFT + 1); } } /* LPC係数次数/LPC係数右シフト量/LPC係数 */ diff --git a/libs/srla_internal/include/srla_internal.h b/libs/srla_internal/include/srla_internal.h index 48a9349..6dba1cf 100644 --- a/libs/srla_internal/include/srla_internal.h +++ b/libs/srla_internal/include/srla_internal.h @@ -12,7 +12,7 @@ /* 内部エンコードパラメータ */ /* プリエンファシスの係数シフト量 */ -#define SRLA_PREEMPHASIS_COEF_SHIFT 5 +#define SRLA_PREEMPHASIS_COEF_SHIFT 4 /* プリエンファシスフィルタの適用回数 */ #define SRLA_NUM_PREEMPHASIS_FILTERS 2 /* LPC係数のビット幅 */ diff --git a/libs/srla_internal/include/srla_utility.h b/libs/srla_internal/include/srla_utility.h index 0dcc15d..db11335 100644 --- a/libs/srla_internal/include/srla_utility.h +++ b/libs/srla_internal/include/srla_utility.h @@ -129,13 +129,13 @@ void SRLAUtility_SRtoLRConversion(int32_t **buffer, uint32_t num_samples); /* プリエンファシスフィルタ初期化 */ void SRLAPreemphasisFilter_Initialize(struct SRLAPreemphasisFilter *preem); -/* プリエンファシスフィルタ係数計算 */ -void SRLAPreemphasisFilter_CalculateCoefficient( - struct SRLAPreemphasisFilter *preem, const int32_t *buffer, uint32_t num_samples); +/* 多段プリエンファシスの係数計算 */ +void SRLAPreemphasisFilter_CalculateMultiStageCoefficients( + struct SRLAPreemphasisFilter *preem, uint32_t num_preem, const int32_t *buffer, uint32_t num_samples); /* プリエンファシス */ void SRLAPreemphasisFilter_Preemphasis( - struct SRLAPreemphasisFilter *preem, int32_t *buffer, uint32_t num_samples); + struct SRLAPreemphasisFilter *preem, int32_t *buffer, uint32_t num_samples); /* デエンファシスを複数回適用 */ void SRLAPreemphasisFilter_MultiStageDeemphasis( diff --git a/libs/srla_internal/src/srla_utility.c b/libs/srla_internal/src/srla_utility.c index 97e79bc..1583e91 100644 --- a/libs/srla_internal/src/srla_utility.c +++ b/libs/srla_internal/src/srla_utility.c @@ -181,44 +181,87 @@ void SRLAPreemphasisFilter_Initialize(struct SRLAPreemphasisFilter *preem) preem->coef = 0; } -/* プリエンファシスフィルタ係数計算 */ -void SRLAPreemphasisFilter_CalculateCoefficient( - struct SRLAPreemphasisFilter *preem, const int32_t *buffer, uint32_t num_samples) +/* 多段プリエンファシスの係数計算 */ +void SRLAPreemphasisFilter_CalculateMultiStageCoefficients( + struct SRLAPreemphasisFilter *preem, uint32_t num_preem, const int32_t *buffer, uint32_t num_samples) { - uint32_t smpl; - int32_t coef; - double corr[2] = { 0.0, 0.0 }; - double curr; + uint32_t i; + double r0, r1, r2; + double curr, succ; + double double_coef[SRLA_NUM_PREEMPHASIS_FILTERS]; + + /* 注意)現段階では2回を前提 */ + SRLA_STATIC_ASSERT(SRLA_NUM_PREEMPHASIS_FILTERS == 2); + SRLA_ASSERT(num_preem == 2); SRLA_ASSERT(preem != NULL); SRLA_ASSERT(buffer != NULL); /* 相関の計算 */ curr = buffer[0]; - for (smpl = 0; smpl < num_samples - 1; smpl++) { - const double succ = buffer[smpl + 1]; - corr[0] += curr * curr; - corr[1] += curr * succ; + succ = buffer[1]; + r0 = r1 = r2 = 0.0; + for (i = 0; i < num_samples - 2; i++) { + const double succsucc = buffer[i + 2]; + r0 += curr * curr; + r1 += curr * succ; + r2 += curr * succsucc; curr = succ; + succ = succsucc; + } + /* i = num_samples - 1 */ + r0 += curr * curr; + r1 += curr * succ; + curr = succ; + r0 += curr * curr; + SRLA_ASSERT((r0 >= r1) && (r0 >= r2)); + + /* 分散が小さい場合は全て0を設定 */ + if (r0 < 1e-6) { + for (i = 0; i < SRLA_NUM_PREEMPHASIS_FILTERS; i++) { + preem[i].coef = 0; + } + return; } - corr[0] += curr * curr; - SRLA_ASSERT(corr[0] >= corr[1]); + /* 分散(=0次相関)で正規化 */ - corr[1] /= corr[0]; + r1 /= r0; + r2 /= r0; + r0 = 1.0; + + /* プリエンファシスの係数計算 */ + { + /* 平方根の2乗 */ + const double sqroot = r1 * r1 * (r0 - r2) * (r0 - r2) - 4.0 * (r0 * r0 - r1 * r1) * (r1 * r1 - r0 * r2); + if (sqroot >= 0.0) { + double det; + double tmpcoef[2] = { 0.0, 0.0 }; + tmpcoef[1] = (r1 * (r0 - r2) - sqrt(sqroot)) / (2.0 * (r0 * r0 - r1 * r1)); + tmpcoef[0] = (tmpcoef[1] * r1 - r2) / (tmpcoef[1] * r0 - r1); + /* ヘッセ行列の行列式 */ + det = 4.0 * (tmpcoef[0] * tmpcoef[0] * r0 - 2.0 * tmpcoef[0] * r1 + r0) * (tmpcoef[1] * tmpcoef[1] * r0 - 2.0 * tmpcoef[1] * r1 + r0); + det -= 4.0 * pow(2.0 * tmpcoef[0] * tmpcoef[1] * r0 - 2.0 * tmpcoef[0] * r1 - 2.0 * tmpcoef[1] * r1 + r0 + r2, 2.0); + if (det > 0.0) { + double_coef[0] = tmpcoef[0]; + double_coef[1] = tmpcoef[1]; + } else { + double_coef[0] = r1; + double_coef[1] = r1 * (r1 * r1 - r2) / (1.0 - r1 * r1); + } + } else { + /* 複素数解の場合は従来通りの係数(1段ごとに分散最小)を設定 */ + double_coef[0] = r1; + double_coef[1] = r1 * (r1 * r1 - r2) / (1.0 - r1 * r1); + } + } /* 固定小数化 */ - if ((corr[0] < 1e-6) || (corr[1] < 0.0)) { - /* 1次相関が負の場合は振動しているためプリエンファシスの効果は薄い */ - coef = 0; - } else { - coef = (int32_t)SRLAUtility_Round(corr[1] * pow(2.0f, SRLA_PREEMPHASIS_COEF_SHIFT)); + for (i = 0; i < SRLA_NUM_PREEMPHASIS_FILTERS; i++) { + int32_t coef = (int32_t)SRLAUtility_Round(double_coef[i] * pow(2.0f, SRLA_PREEMPHASIS_COEF_SHIFT)); /* 丸め込み */ - if (coef >= (1 << (SRLA_PREEMPHASIS_COEF_SHIFT - 1))) { - coef = (1 << (SRLA_PREEMPHASIS_COEF_SHIFT - 1)) - 1; - } + coef = SRLAUTILITY_INNER_VALUE(coef, -(1 << SRLA_PREEMPHASIS_COEF_SHIFT), (1 << SRLA_PREEMPHASIS_COEF_SHIFT) - 1); + preem[i].coef = coef; } - - preem->coef = coef; } /* プリエンファシス */