3

该站点上还有其他问题和答案表明,要创建回声或延迟效果,您只需添加一个音频样本和过去存储的音频样本。因此,我有以下 Java 类:

public class DelayAMod extends AudioMod {

private int delay = 500;
private float decay = 0.1f;
private boolean feedback = false;

private int delaySamples;
private short[] samples;
private int rrPointer;

@Override
public void init() {
    this.setDelay(this.delay);
    this.samples = new short[44100];
    this.rrPointer = 0;
}

public void setDecay(final float decay) {
    this.decay = Math.max(0.0f, Math.min(decay, 0.99f));
}

public void setDelay(final int msDelay) {
    this.delay = msDelay;
    this.delaySamples = 44100 / (1000/this.delay);
    System.out.println("Delay samples:"+this.delaySamples);
}

@Override
public short process(short sample) {
    System.out.println("Got:"+sample);
    if (this.feedback) {
        //Delay should feed back into the loop:
        sample = (this.samples[this.rrPointer] = this.apply(sample));
    } else {
        //No feedback - store base data, then add echo:
        this.samples[this.rrPointer] = sample;
        sample = this.apply(sample);
    }
    ++this.rrPointer;
    if (this.rrPointer >= this.samples.length) {
        this.rrPointer = 0;
    }
    System.out.println("Returning:"+sample);
    return sample;
}

private short apply(short sample) {
    int loc = this.rrPointer - this.delaySamples;
    if (loc < 0) {
        loc += this.samples.length;
    }
    System.out.println("Found:"+this.samples[loc]+" at "+loc);
    System.out.println("Adding:"+(this.samples[loc] * this.decay));
    return (short)Math.max(Short.MIN_VALUE, Math.min(sample + (int)(this.samples[loc] * this.decay), (int)Short.MAX_VALUE));
}
}

它一次从输入流中接受一个 16 位样本,找到一个较早的样本,并将它们相应地相加。然而,输出只是可怕的嘈杂静态,尤其是当衰减提高到实际上会导致任何明显结果的水平时。将衰减降低到 0.01 几乎无法让原始音频通过,但此时肯定没有回声。

基本故障排除事实:

  • 如果跳过此处理,音频流听起来不错。
  • 如果衰减为 0(无需添加),音频流听起来不错。
  • 存储的样本确实以正确的顺序和正确的位置存储和访问。
  • 存储的样本正在衰减并正确添加到输入样本中。
  • 调用process()toreturn sample的所有数字正是我对这个算法的期望,即使在这个类之外仍然如此。

问题似乎来自于简单地将带符号的短路相加,由此产生的波形绝对是一场灾难。我已经在很多地方看到了这种特定的方法——C#、C++,甚至在微控制器上——那么为什么它在这里失败得这么难呢?

编辑:看来我一直在做这完全错误的事情。我不知道是 FFmpeg/avconv 还是其他因素,但我在这里没有使用正常的 PCM 信号。通过波形图,以及对音调发生器的失败尝试和结果分析,我确定这是某种版本的差分脉冲编码调制;音高是由一个样本到下一个样本的变化决定的,将纯正弦波上的预期“音量”乘数减半实际上会降低音高并使音量保持不变。(在非正弦序列上使用音量乘数会产生与此回声算法相同的静态。)因为此算法和其他 DSP 算法旨在用于线性脉冲编码调制,我将需要一些方法来首先获得正确的音频流。

4

1 回答 1

0

除非您有明显的剪裁,否则它肯定可以工作。

例如,这是一个包含两列的文本文件。最左边的列是 16 位输入。第二列是第一列和延迟了 4001 个样本的版本之和。采样率为 22KHz。

第二列中的每个样本都是 x[k] 和 x[k-4​​001] 求和的结果(例如 y[5000] = x[5000] + x[999] = -13840 + 9181 = -4659)你可以清楚播放第二列中的样本时听到回声信号。

用你的代码试试这个信号,看看你是否得到相同的结果。

于 2013-05-15T10:11:02.783 回答