帮助动态范围压缩功能(音频)

时间:2010-05-25 20:03:14

标签: c# function audio

我正在编写一个用于进行动态范围压缩的C#功能(一种音频效果,基本上可以压缩瞬态峰值并放大其他所有内容以产生更响亮的声音)。我写了一个函数(我认为):

alt text http://www.freeimagehosting.net/uploads/feea390f84.jpg

public static void Compress(ref short[] input, double thresholdDb, double ratio)
{
    double maxDb = thresholdDb - (thresholdDb / ratio);
    double maxGain = Math.Pow(10, -maxDb / 20.0);

    for (int i = 0; i < input.Length; i += 2)
    {
        // convert sample values to ABS gain and store original signs
        int signL = input[i] < 0 ? -1 : 1;
        double valL = (double)input[i] / 32768.0;
        if (valL < 0.0)
        {
            valL = -valL;
        }
        int signR = input[i + 1] < 0 ? -1 : 1;
        double valR = (double)input[i + 1] / 32768.0;
        if (valR < 0.0)
        {
            valR = -valR;
        }

        // calculate mono value and compress
        double val = (valL + valR) * 0.5;
        double posDb = -Math.Log10(val) * 20.0;
        if (posDb < thresholdDb)
        {
            posDb = thresholdDb - ((thresholdDb - posDb) / ratio);
        }

        // measure L and R sample values relative to mono value
        double multL = valL / val;
        double multR = valR / val;

        // convert compressed db value to gain and amplify
        val = Math.Pow(10, -posDb / 20.0);
        val = val / maxGain;

        // re-calculate L and R gain values relative to compressed/amplified
        // mono value
        valL = val * multL;
        valR = val * multR;

        double lim = 1.5; // determined by experimentation, with the goal
            // being that the lines below should never (or rarely) be hit
        if (valL > lim)
        {
            valL = lim;
        }
        if (valR > lim)
        {
            valR = lim;
        }

        double maxval = 32000.0 / lim; 

        // convert gain values back to sample values
        input[i] = (short)(valL * maxval); 
        input[i] *= (short)signL;
        input[i + 1] = (short)(valR * maxval); 
        input[i + 1] *= (short)signR;
    }
}

我称它的threshold值介于10.0 db和30.0 db之间,比率介于1.5和4.0之间。此功能肯定会产生更响亮的整体声音,但具有不可接受的失真水平,即使在低阈值和低比率时也是如此。

有人能看到这个功能有什么问题吗?我是否正确处理立体声方面(该功能假定立体声输入)?当我(模糊地)理解事物时,我不想单独压缩两个通道,所以我的代码试图压缩“虚拟”单声道样本值,然后分别对L和R样本值应用相同程度的压缩。然而,不确定我是否正确。

我认为问题的一部分可能是我的功能的“硬拐点”,当超过阈值时,它突然开始压缩。我想我可能需要使用这样的“软膝盖”:

alt text http://www.freeimagehosting.net/uploads/4c1040fda8.jpg

有人建议修改我的功能以产生柔软的膝盖曲线吗?

2 个答案:

答案 0 :(得分:2)

开源Skype Voice Changer项目包含一个由Scott Stillwell编写的许多不错的压缩器的C#端口,所有压缩器都带有可配置的参数:

第一个看起来它有能力做软膝盖,虽然这样做的参数不会暴露。

答案 1 :(得分:1)

我认为您对如何进行压缩的基本理解是错误的(抱歉;))。这不是关于“压缩”个别样本值;这将彻底改变波形并产生严重的谐波失真。您需要评估许多样本的输入信号量(我必须使用Google获取正确的公式),然后使用此值将更多逐渐变化的乘数应用于输入样本以生成输出。

如果您很难找到常用的技术,那么kvraudio.com/forum上的DSP论坛可能会指出您正确的方向。