代码之家  ›  专栏  ›  技术社区  ›  MusiGenesis

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

  •  6
  • MusiGenesis  · 技术社区  · 14 年前

    我正在编写一个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 回复  |  直到 14 年前
        1
  •  1
  •   Conrad Albrecht    14 年前

    我认为您对如何进行压缩的基本理解是错误的(抱歉;)。这与“压缩”单个采样值无关;这将从根本上改变波形并产生严重的谐波失真。您需要对许多样本的输入信号量进行评估(我必须谷歌搜索正确的公式),并使用此公式对输入样本应用一个更为渐变的乘数以生成输出。

    在kvraudio.com/forum上的DSP论坛,如果你很难找到通常的技术,可能会为你指明正确的方向。

        2
  •  2
  •   Mark Heath    14 年前

    开源 Skype Voice Changer 该项目包括一个到C的端口,该端口由 Scott Stillwell ,所有配置参数:

    第一个看起来像有能力做软膝盖,尽管这样做的参数没有暴露。