音频标准化的Java算法

音频标准化的Java算法,java,math,audio,Java,Math,Audio,我正在尝试将语音文件正常化 具体来说,当音频文件包含音量峰值时,我会尝试将其调平,这样安静的部分声音会更大,峰值也会更安静 除了从这项工作中学到的知识外,我对音频处理知之甚少。而且,我的数学很糟糕 我做了一些研究,Xuggle网站提供了一个示例,显示了使用以下代码减少音量:() 步骤2:规范化所有值: 在类似于步骤1的循环中,使用规范化值替换缓冲区,调用: buffer.put(i, normalize(buffer.get(i)); public short normalize(sh

我正在尝试将语音文件正常化


具体来说,当音频文件包含音量峰值时,我会尝试将其调平,这样安静的部分声音会更大,峰值也会更安静

除了从这项工作中学到的知识外,我对音频处理知之甚少。而且,我的数学很糟糕

我做了一些研究,Xuggle网站提供了一个示例,显示了使用以下代码减少音量:()

步骤2:规范化所有值: 在类似于步骤1的循环中,使用规范化值替换缓冲区,调用:

    buffer.put(i, normalize(buffer.get(i));

public short normalize(short value) {
    if (isBackgroundNoise(value))
        return value;

    short rawMin = // min from step1
    short rawMax = // max from step1
    short targetRangeMin = 1000;
    short targetRangeMax = 8000;

    int abs = Math.abs(value);
    double a = (abs - rawMin) * (targetRangeMax - targetRangeMin);
    double b = (rawMax - rawMin);
    double result = targetRangeMin + ( a/b );

     // Copy the sign of value to result.
    result = Math.copySign(result,value);
    return (short) result;
}
问题:
  • 这是尝试规范化音频文件的有效方法吗
  • normalize()
    中的数学有效吗
  • 为什么这会导致文件变得嘈杂,而演示代码中的类似方法却没有

我认为“最小采样值”的概念不是很有意义,因为采样值只是表示特定时刻声波的当前“高度”。即,其绝对值将在音频剪辑的峰值和零之间变化。因此,使用
targetRangeMin
似乎是错误的,并且可能会导致波形的某些失真

我认为更好的方法可能是使用某种权重函数,根据样本大小减少样本值。也就是说,较大的值比较小的值减少了很大的百分比。这也会带来一些失真,但可能不是很明显

编辑:以下是此类方法的示例实现:

public short normalize(short value) {
    short rawMax = // max from step1
    short targetMax = 8000;

    //This is the maximum volume reduction
    double maxReduce = 1 - targetMax/(double)rawMax;

    int abs = Math.abs(value);
    double factor = (maxReduce * abs/(double)rawMax);

    return (short) Math.round((1 - factor) * value); 
}
作为参考,这是您的算法对振幅为10000的正弦曲线所做的:

这解释了音频质量在标准化后变得更差的原因

这是使用我建议的
normalize
方法运行后的结果:

音频的“规范化”是提高音频级别的过程,使最大值等于某个给定值,通常是最大可能值。今天,在另一个问题中,有人解释了如何做到这一点(见#1):


然而,你接着会说“具体来说,如果音频文件包含音量峰值,我会尝试将其调平,这样安静的部分会更响亮,而峰值会更安静。”这称为“压缩”或“限制”(不要与MP3编码中使用的压缩类型混淆!)。您可以在此处阅读更多有关内容:

一个简单的压缩器并不特别难实现,但是你说你的数学“非常糟糕”,所以你可能想找到一个已经建成的。您可能能够找到在中实现的压缩器,并将其从C转换为Java。据我所知,压缩机的java实现中唯一一个可用的(而且不是很好)是

作为解决问题的另一种方法,您可以将文件标准化为每段1/2秒,然后使用线性插值连接用于每段的增益值。您可以在此处阅读有关音频线性插值的内容:


我不知道源代码是否可用,但这是您可以尝试的其他内容。

“我正在尝试将其调平,以便安静的部分声音更大,峰值更安静。”-这就是所谓的,与标准化不同。
    buffer.put(i, normalize(buffer.get(i));

public short normalize(short value) {
    if (isBackgroundNoise(value))
        return value;

    short rawMin = // min from step1
    short rawMax = // max from step1
    short targetRangeMin = 1000;
    short targetRangeMax = 8000;

    int abs = Math.abs(value);
    double a = (abs - rawMin) * (targetRangeMax - targetRangeMin);
    double b = (rawMax - rawMin);
    double result = targetRangeMin + ( a/b );

     // Copy the sign of value to result.
    result = Math.copySign(result,value);
    return (short) result;
}
public short normalize(short value) {
    short rawMax = // max from step1
    short targetMax = 8000;

    //This is the maximum volume reduction
    double maxReduce = 1 - targetMax/(double)rawMax;

    int abs = Math.abs(value);
    double factor = (maxReduce * abs/(double)rawMax);

    return (short) Math.round((1 - factor) * value); 
}