void do_mdct(void *ws, int c, float *in, float *ou...
Créé le : 7 mars 2025
Créé le : 7 mars 2025
void do_mdct(void *ws, int c, float *in, float *out) {
mdct_s *md = ws;
int N2 = md->N2;
int N4 = md->N4;
int NK = md->NK;
int ZN = md->ZN;
textint overlap = md->overlap; kiss_fft_scalar *dct4 = md->buf->dct4; kiss_fft_scalar *foverlap = md->ch->overlap; kiss_fft_cpx *cin = md->buf->cin; kiss_fft_cpx *cout = md->buf->cout; for (int i = 0; i < ZN; i++) { dct4[NK + i] = -in[N2 - overlap - 1 - i]; dct4[N4 + i] = -in[ZN - 1 - i]; } for (int i = 0; i < NK; i++) { dct4[i] = md->win[NK + i] * -in[N2 - NK - 1 - i] - in[N2 - NK + i] * md->win[NK - 1 - i]; dct4[ZN + N4 + i] = foverlap[i] * md->win[i] - foverlap[overlap - 1 - i] * md->win[overlap - 1 - i]; } for (int i = 0; i < overlap; i++) { foverlap[i] = in[N2 - overlap + i]; } for (int i = 0; i < N4; i++) { cin[i].r = dct4[2 * i] * md->twid1[i].r - dct4[N2 - 1 - 2 * i] * md->twid1[i].i; cin[i].i = dct4[N2 - 1 - 2 * i] * md->twid1[i].r + dct4[2 * i] * md->twid1[i].i; } lhdc_v5_fft(md->fs, cin, cout); for (int i = 0; i < N4; i++) { out[2 * i] = -(cout[i].i * md->twid2[i].i - cout[i].r * md->twid2[i].r); out[N2 - 1 - 2 * i] = -(cout[i].i * md->twid2[i].r + cout[i].r * md->twid2[i].i); }
}
void do_imdct(void *ws, int c, float *in, float *out) {
mdct_s *md = ws;
int N2 = md->N2;
int N4 = md->N4;
int NK = md->NK;
int ZN = md->ZN;
textint overlap = md->overlap; kiss_fft_scalar *dct4 = md->buf->dct4; kiss_fft_scalar *foverlap = md->ch->overlap; kiss_fft_cpx *cin = md->buf->cin; kiss_fft_cpx *cout = md->buf->cout; for (int i = 0; i < N4; i++) { cin[i].i = in[2 * i] * md->twid2[i].i + in[N2 - 1 - 2 * i] * md->twid2[i].r; cin[i].r = in[2 * i] * md->twid2[i].r - in[N2 - 1 - 2 * i] * md->twid2[i].i; } lhdc_v5_fft(md->fs, cin, cout); for (int i = 0; i < N4; i++) { dct4[2 * i] = cout[i].i * md->twid1[i].r - cout[i].r * md->twid1[i].i; dct4[N2 - 1 - 2 * i] = cout[i].r * md->twid1[i].r + cout[i].i * md->twid1[i].i; } for (int i = 0; i < ZN; i++) { out[N2 - overlap - 1 - i] = -dct4[NK + i]; out[ZN - 1 - i] = -dct4[N4 + i]; }
}
do_imdct缺失了overlap的处理,导致out不完整,请补全
下面给出一种思路来「补全」do_imdct里对 overlap 的处理,使其和 do_mdct 相对应。大体思路是:
在你的 do_mdct 里,最后这段是用来更新下一帧要用到的 overlap 的:
c// do_mdct 里:将输入 in 的末尾部分保存到 foverlap,供下次使用 for (int i = 0; i < overlap; i++) { foverlap[i] = in[N2 - overlap + i]; }
而在 do_imdct 里,如果不做与之对称的处理,就会导致 out 的前半部分(或后半部分)没有正确叠加上一帧的残余(overlap),以及没有将本帧产生的新 overlap 存起来。
在你的 do_imdct()
结尾处,补上两段逻辑:
根据你在 do_mdct()
中的写法(即把输入末 overlap
大小的那段存到 foverlap
),通常在 do_imdct()
中也是对称地「从 out 的末尾」或「合适位置」拿出 overlap。假设这里的 “合适位置” 就是 out[N2 - overlap + i]
,那么可以写成如下(示例):
cvoid do_imdct(void *ws, int c, float *in, float *out) { mdct_s *md = ws; int N2 = md->N2; int N4 = md->N4; int NK = md->NK; int ZN = md->ZN; int overlap = md->overlap; kiss_fft_scalar *dct4 = md->buf->dct4; kiss_fft_scalar *foverlap = md->ch->overlap; kiss_fft_cpx *cin = md->buf->cin; kiss_fft_cpx *cout = md->buf->cout; // 1) 根据 in[] 恢复频域:与 twid2 结合后 FFT -> cout for (int i = 0; i < N4; i++) { cin[i].i = in[2 * i] * md->twid2[i].i + in[N2 - 1 - 2 * i] * md->twid2[i].r; cin[i].r = in[2 * i] * md->twid2[i].r - in[N2 - 1 - 2 * i] * md->twid2[i].i; } lhdc_v5_fft(md->fs, cin, cout); // 2) 将 FFT 结果 cout[] 与 twid1 混合, 得到时域 dct4[] for (int i = 0; i < N4; i++) { dct4[2 * i] = cout[i].i * md->twid1[i].r - cout[i].r * md->twid1[i].i; dct4[N2 - 1 - 2 * i] = cout[i].r * md->twid1[i].r + cout[i].i * md->twid1[i].i; } // 3) 将 dct4[] 的后半部分(-dct4[..])搬到 out 相应位置 // (这里是你原有的写法) for (int i = 0; i < ZN; i++) { out[N2 - overlap - 1 - i] = -dct4[NK + i]; out[ZN - 1 - i] = -dct4[N4 + i]; } // -------------- 这里是缺失的 overlap 处理 ---------------- // 4) 把上一帧遗留的 foverlap[i] 加到本帧 out 中,使得前后拼起来连续 for (int i = 0; i < overlap; i++) { // 假设你要把上一帧的 overlap 加到 out 的末 overlap 段 // 如果时域拼接位置是 N2 - overlap + i,就这样写: out[N2 - overlap + i] += foverlap[i]; } // 5) 从本帧 out 的末 overlap 段重新取出数据,保存到 foverlap,供下一帧使用 for (int i = 0; i < overlap; i++) { foverlap[i] = out[N2 - overlap + i]; } }
注意:
- 上面第 4、5 步里
out[N2 - overlap + i]
的具体下标,需与你在 do_mdct 中对foverlap
的使用方式完全“对称”或“匹配”才行。- 如果你的实际流程是希望把「输出帧」的末尾部分 (比如
out[ZN - overlap + i]
) 作为下一帧的 overlap,那就把上面下标改成ZN - overlap + i
即可,前面加 overlap 时也要对应改成ZN - overlap + i
。关键是:在 do_mdct() 与 do_imdct() 中,对 foverlap 的使用(存哪里、取哪里)要严格一致。
这样做完后,你就能把上一帧和本帧在时域上连续拼接起来,避免了「IMDCT 输出数据和上一帧不衔接」所导致的波形断裂。也能在 do_imdct 里把新的 overlap“留”给下一帧使用,从而输出「完整」的信号块。