Skip to content

Commit

Permalink
improve pre-emphasis filter.
Browse files Browse the repository at this point in the history
  • Loading branch information
aikiriao committed Jul 12, 2024
1 parent 6660a1a commit 71e832f
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 43 deletions.
5 changes: 2 additions & 3 deletions libs/srla_decoder/src/srla_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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係数 */
Expand Down
20 changes: 9 additions & 11 deletions libs/srla_encoder/src/srla_encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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係数右シフト量 */
Expand Down Expand Up @@ -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係数 */
Expand Down
2 changes: 1 addition & 1 deletion libs/srla_internal/include/srla_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

/* 内部エンコードパラメータ */
/* プリエンファシスの係数シフト量 */
#define SRLA_PREEMPHASIS_COEF_SHIFT 5
#define SRLA_PREEMPHASIS_COEF_SHIFT 4
/* プリエンファシスフィルタの適用回数 */
#define SRLA_NUM_PREEMPHASIS_FILTERS 2
/* LPC係数のビット幅 */
Expand Down
8 changes: 4 additions & 4 deletions libs/srla_internal/include/srla_utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
91 changes: 67 additions & 24 deletions libs/srla_internal/src/srla_utility.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/* プリエンファシス */
Expand Down

0 comments on commit 71e832f

Please sign in to comment.