2

我使用 apache commons 数学库来转换我的音频样本缓冲区上的 FFt 和 IFFT。FFT 的输出给了我一个复数数组。频率反映在中间。使用 4096 个样本的样本缓冲区大小,我得到 2048 个有用的复数。我的效果序列的结构

我在 Java 中有两种实现,一种在 IFFT 之前遍历最终数组,并计算应该从中获取复数的位置的插值。所以基本上我正在做的是在另一个频率范围内扭曲复数。

FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] freq, inverse, freqn;

for(int c = 0; c < in.length; c++){

    freq = fft.transform(in[c], TransformType.FORWARD);
    freqn = new Complex[freq.length];

    freqn[0] = Complex.valueOf(freq[0].getReal(), freq[0].getImaginary());

    for (int i = 1; i <= freq.length/2; i++) {

        double fOrig = i / factor + shift;

        int left = (int) Math.floor(fOrig);
        int right = (int) Math.ceil(fOrig);
        double weighting = fOrig - left;

        double new_Re = 0, new_Im = 0;

        if(left > 0 && left < freq.length / 2 && right > 0 && right < freq.length / 2){
            new_Re = interpolate(freq[left].getReal(), freq[right].getReal(), weighting);
            new_Im = interpolate(freq[left].getImaginary(), freq[right].getImaginary(), weighting);
        }
        freqn[i] = Complex.valueOf(new_Re, new_Im);
        freqn[freq.length-i] = Complex.valueOf(new_Re, new_Im);
    }
    inverse = fft.transform(freqn, TransformType.INVERSE);

    for(int i = 0; i < inverse.length; i++){
        in[c][i] = inverse[i].getReal();
    }
}

由于输入音频信号的采样率,我从一个音高频率中获得了多个音高频率,因此这种实现主要在高音区域产生具有副作用的声音。我的其他实现计算传入复数的幅度和相位。然后它仅将幅度标度扭曲到新位置,然后在原始相位值和新幅度值的帮助下计算新复数。在矩形到极坐标和矩形之间转换时,我失去了我的标志。因为我只改变了复数向量的长度,所以我可以在输出复数上强制输入符号。

FastFourierTransformer fft = new FastFourierTransformer(DftNormalization.STANDARD);
Complex[] freq, inverse;

for(int c = 0; c < in.length; c++){

    freq = fft.transform(in[c], TransformType.FORWARD);

    double[] ampl = new double[freq.length];
    double[] angl = new double[freq.length];

    double re, im;

    boolean[] unitRe = new boolean[freq.length];
    boolean[] unitIm = new boolean[freq.length];

    double fctr = factor;

    for(int f = 0; f < freq.length; f++){
        re = freq[f].getReal();
        im = freq[f].getImaginary();
        unitRe[f] = re >= 0;
        unitIm[f] = im >= 0;

        ampl[f] = op.magn(re, im);
        angl[f] = op.agl(re, im);
    }

    for(int f = 0; f < freq.length; f++){
        int val = f < freq.length / 2 ? f : freq.length / 2 - (f - freq.length / 2);
        double weighting = ((double)val / fctr + shift) % 1;

        int left = (int) Math.floor(val / fctr + shift);
        int right = (int) Math.ceil(val / fctr + shift);
        double new_ampl = 0;

        if(left >= 0 && left < freq.length / 2 && right >= 0 && right < freq.length / 2){
            new_ampl = interpolate(ampl[left], ampl[right], weighting);
        }

        re = op.real(new_ampl, angl[f]);
        im = op.imag(new_ampl, angl[f]);

        re = unitRe[f] ? Math.abs(re) : Math.abs(re) * -1;
        im = unitIm[f] ? Math.abs(im) : Math.abs(im) * -1;

        freq[f] = Complex.valueOf(re, im);
    }

    inverse = fft.transform(freq, TransformType.INVERSE);

    for(int i = 0; i < inverse.length; i++){
        in[c][i] = inverse[i].getReal();
    }
}

第二个实现听起来比第一个好得多。它实际上甚至比我使用的大多数 Dj 应用程序听起来更好,但我不知道为什么?难道我做错了什么?我在 Java 中找不到任何其他实现可以比较。他们通常只是用幅度和相位在一个新的尺度上扭曲整个频率尺度,还是他们只是把幅度和强迫它放到另一个尺度的原始相位上?

4

1 回答 1

2

您的第二种算法类似于时间音高修改的相位声码器方法。据报道,许多音频处理库使用相位声码器技术的变体,但通常只有在有足够的处理能力可用的情况下。

于 2016-08-04T19:35:32.217 回答