如何在Python中放大声音而不失真

如何在Python中放大声音而不失真,python,audio,Python,Audio,我正在尝试对声音文件进行简单的音量调整。我正在使用Python2.7和以下内容 图书馆: import numpy as np import scipy.io.wavfile as wv import matplotlib.pyplot as plt import pyaudio import wave 我尝试了两种方法,我试图将声音放大2倍,即n=2。第一种是从这里开始改变动态范围限制器方法(): 在这两种方法中,文件听起来都失真了。在振幅接近临界值的点上,音乐的声音会断断续

我正在尝试对声音文件进行简单的音量调整。我正在使用Python2.7和以下内容

图书馆:

import numpy as np

import scipy.io.wavfile as wv

import matplotlib.pyplot as plt

import pyaudio  

import wave  
我尝试了两种方法,我试图将声音放大2倍,即n=2。第一种是从这里开始改变动态范围限制器方法():


在这两种方法中,文件听起来都失真了。在振幅接近临界值的点上,音乐的声音会断断续续,噼啪作响。我认为这是因为它在阈值附近“变平”。我尝试在限制器函数中应用指数函数,但即使我使其非常快地减小,它也不能完全消除噼啪声。如果我改变n=1.5,声音不会失真。如果有人能给我一些关于如何消除爆裂失真或其他音量调制代码链接的建议,我将不胜感激。

这可能不是100%的主题,但也许这对你们来说很有趣。如果你不需要做实时处理,事情会变得更容易。极限压缩和动态压缩可视为应用动态传递函数。此函数仅将输入映射到输出值。然后,线性函数返回原始音频,“曲线”函数进行压缩或扩展。应用传递函数非常简单

import numpy as np
from scipy.interpolate import interp1d
from scipy.io import wavfile

def apply_transfer(signal, transfer, interpolation='linear'):
    constant = np.linspace(-1, 1, len(transfer))
    interpolator = interp1d(constant, transfer, interpolation)
    return interpolator(signal)
限制或压缩只是选择不同传递函数的一种情况:

# hard limiting
def limiter(x, treshold=0.8):
    transfer_len = 1000
    transfer = np.concatenate([ np.repeat(-1, int(((1-treshold)/2)*transfer_len)),
                                np.linspace(-1, 1, int(treshold*transfer_len)),
                                np.repeat(1, int(((1-treshold)/2)*transfer_len)) ])
    return apply_transfer(x, transfer)

# smooth compression: if factor is small, its near linear, the bigger it is the
# stronger the compression
def arctan_compressor(x, factor=2):
    constant = np.linspace(-1, 1, 1000)
    transfer = np.arctan(factor * constant)
    transfer /= np.abs(transfer).max()
    return apply_transfer(x, transfer)
本例假设16位单声道wav文件作为输入:

sr, x = wavfile.read("input.wav")
x = x / np.abs(x).max() # x scale between -1 and 1

x2 = limiter(x)
x2 = np.int16(x2 * 32767)
wavfile.write("output_limit.wav", sr, x2)

x3 = arctan_compressor(x)
x3 = np.int16(x3 * 32767)
wavfile.write("output_comp.wav", sr, x3)

也许这段干净的离线代码可以帮助您对实时代码进行基准测试。

这可能不是100%的主题,但也许这对您来说很有趣。如果你不需要做实时处理,事情会变得更容易。极限压缩和动态压缩可视为应用动态传递函数。此函数仅将输入映射到输出值。然后,线性函数返回原始音频,“曲线”函数进行压缩或扩展。应用传递函数非常简单

import numpy as np
from scipy.interpolate import interp1d
from scipy.io import wavfile

def apply_transfer(signal, transfer, interpolation='linear'):
    constant = np.linspace(-1, 1, len(transfer))
    interpolator = interp1d(constant, transfer, interpolation)
    return interpolator(signal)
限制或压缩只是选择不同传递函数的一种情况:

# hard limiting
def limiter(x, treshold=0.8):
    transfer_len = 1000
    transfer = np.concatenate([ np.repeat(-1, int(((1-treshold)/2)*transfer_len)),
                                np.linspace(-1, 1, int(treshold*transfer_len)),
                                np.repeat(1, int(((1-treshold)/2)*transfer_len)) ])
    return apply_transfer(x, transfer)

# smooth compression: if factor is small, its near linear, the bigger it is the
# stronger the compression
def arctan_compressor(x, factor=2):
    constant = np.linspace(-1, 1, 1000)
    transfer = np.arctan(factor * constant)
    transfer /= np.abs(transfer).max()
    return apply_transfer(x, transfer)
本例假设16位单声道wav文件作为输入:

sr, x = wavfile.read("input.wav")
x = x / np.abs(x).max() # x scale between -1 and 1

x2 = limiter(x)
x2 = np.int16(x2 * 32767)
wavfile.write("output_limit.wav", sr, x2)

x3 = arctan_compressor(x)
x3 = np.int16(x3 * 32767)
wavfile.write("output_comp.wav", sr, x3)

也许这段干净的离线代码可以帮助您对实时代码进行基准测试。

感谢您的回复,Frank Zalkow。我实际上不需要实时处理,所以这段代码要快得多。我试着运行这段代码,之后我的输出听起来更加失真。这听起来像是“硬摇滚”版的原声。我在应用限制器和arctan_压缩变换之前(左)和之后(右)绘制了声音文件。你能解释为什么所有的值都是负值吗?图表如下:。请参见下面的示例:在应用限制器或arctan_压缩器之前,请在-1和+1之间缩放音频信号。之后,将其重新缩放到最大振幅(16位文件为32767)。这有帮助吗?在从音频文件中读取x后,我发现了问题所在,它需要被转换为浮点数,否则它将从0变为-1,而不是从1变为-1。谢谢哦,是的!我使用Python3,它会自动进行转换。。。对,在Python 2上,在缩放之前将其转换为float。尽管此方法似乎合适,但这种压缩(即单个样本振幅的非线性变换)将产生失真的声音,并且远离最大允许振幅。这是由于谐波的性质和我们听到的方式——当使用非线性缩放时,我们确实扭曲了振幅的比例,从而扭曲了波。即使声音不大,音频也会听起来“驱动过度”。您可以使缩放更线性,但这样就不会压缩太多。线性缩放系数取决于当地环境会更好。谢谢你的回复,弗兰克·扎尔科夫。我实际上不需要实时处理,所以这段代码要快得多。我试着运行这段代码,之后我的输出听起来更加失真。这听起来像是“硬摇滚”版的原声。我在应用限制器和arctan_压缩变换之前(左)和之后(右)绘制了声音文件。你能解释为什么所有的值都是负值吗?图表如下:。请参见下面的示例:在应用限制器或arctan_压缩器之前,请在-1和+1之间缩放音频信号。之后,将其重新缩放到最大振幅(16位文件为32767)。这有帮助吗?在从音频文件中读取x后,我发现了问题所在,它需要被转换为浮点数,否则它将从0变为-1,而不是从1变为-1。谢谢哦,是的!我使用Python3,它会自动进行转换。。。对,在Python 2上,在缩放之前将其转换为float。尽管此方法似乎合适,但这种压缩(即单个样本振幅的非线性变换)将产生失真的声音,并且远离最大允许振幅。这是由于谐波的性质和我们听到的方式——当使用非线性缩放时,我们确实扭曲了振幅的比例,从而扭曲了波。即使声音不大,音频也会听起来“驱动过度”。您可以使缩放更线性,但这样就不会压缩太多。系数依赖于本地上下文的线性缩放效果更好。