在字节数组上模拟吉他放大器的失真

Simulate distortion of guitar amplifier on byte array

如果我(在 Java)有一个包含音频样本的 double[] 数组,范围从 -1 到 1,我可以播放它,并且生成听起来像正在弹奏的吉他弦, 有没有什么方法可以模拟放大器失真对这些样本的影响?

对于术语 "distortion" 的含糊不清,我深表歉意,但我指的是类似于将吉他放大器设置为 "distortion" 的任何效果。我已经拥有的声音听起来像原声吉他或没有失真的电吉他(设置为 "clean"),那么我怎样才能改变阵列以听起来更像您对摇滚或电吉他的期望金属镶嵌?

当前样本集使用以下方法计算:

double[] samples = new double[duration]; //duration = seconds * sampleRate
int period = (float)sampleRate / (float)frequency;
double[] buf = new double[period]; //a ring buffer used for the sound generation
int count = 0, c1 = 1, c2 = 2;
for(int i=0; i<duration; i++){
    if(count <= period)count = 0;
    if(c1 <= period)c1 = 0;
    if(c2 <= period)c2 = 0;
    if(i < period){
        buf[count] = rand.nextDouble() * 2 - 1; //rand being a Random
    }
    else{
        buff[count] = (buff[c1] + buff[c2]) / 2;
    }
    samples[i] = buff[count];
    count++;
    c1++;
    c2++;
}

失真主要分为三种类型:

  • 硬失真:信号的简单削波

    for (int i = 0; i < duration; i++)
    {
        double sample = samples[i] * gain_pre;
        if (sample > clip)
            sample = clip;
        else
        if (sample < -clip)
            sample = -clip;
        samples[i] = sample * gain_post;
    }
    
  • 正常失真:信号的指数平滑缩放

    double max = 1.0 / (1.0 - exp(-gain_pre));
    for (int i = 0; i < duration; i++)
    {
        double sample = samples[i] * gain_pre;
        double z = (sample < 0.0) ? (-1.0 + exp(sample)) :
                                    (1.0 - exp(-sample));   
        samples[i] = z * max * gain_post;
    }
    
  • 软失真:与上面相同,但使用 arc-tan(大概更激进)

    double max = 1.0 / atan(gain_pre);
    for (int i = 0; i < duration; i++)
    {
        samples[i] = atan(samples[i] * gain_pre) * max * gain_post;
    }
    

变量:

  • gain_pregain_post:前置增益和Post增益参数
  • clip:硬失真信号的最大值
  • samples:你计算的样本序列

参考资料/更多信息:

http://cp-gfx.sourceforge.net/(下载源码在/src/effects/中查看)

https://en.wikipedia.org/wiki/Distortion_(music)#Theory_and_circuits