音频标准化的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);
}