使用 python 为音调添加随机噪声
Add random noise to tone using python
我正在尝试检测录音中突然发出的巨响。我发现这样做的一种方法是创建音频的频谱图并添加每一列的值。通过绘制每列中值的总和,每次突然出现巨响时,都可以看到尖峰。问题是,在我的用例中,我需要在录制音频时播放蜂鸣音(频率为 2350 Hz)。蜂鸣声的频谱图如下所示:
如您所见,在这个蜂鸣声(这是一种频率为 2350 Hz 的简单音调)的开始和结束处,存在其他频率,但我未能成功去除。在对频谱图的列求和时,在蜂鸣声的开始和结束时,这些不需要的频率会导致尖峰。我想避免这种情况,因为我不想让我的哔哔声被检测为突然的巨响。请参阅下面的频谱图以供参考:
这是频谱图中每列总和的图形:
显然,我想避免在我的算法中出现误报。所以我需要一些方法来消除由哔哔声开始和结束引起的尖峰。到目前为止,我的一个想法是在上面的蜂鸣声谱图中的 2350 Hz 线以下添加具有高于 and/or 的低分贝值的随机噪声。理想情况下,这会创建一个听起来与原始音调非常相似的音调,但当我将列中的所有值相加时,它不会创建尖峰,而是会创建更多的平台。这个想法是解决我的问题的可行方法吗?如果是这样,我将如何使用 python 来创建具有随机噪声的蜂鸣声?对于我忽略的问题,还有其他更简单的解决方案吗?
目前,我正在使用以下代码生成提示音:
import math
import wave
import struct
audio = []
sample_rate = 44100.0
def append_sinewave(
freq=440.0,
duration_milliseconds=500,
volume=1.0):
"""
The sine wave generated here is the standard beep. If you want something
more aggresive you could try a square or saw tooth waveform. Though there
are some rather complicated issues with making high quality square and
sawtooth waves... which we won't address here :)
"""
global audio # using global variables isn't cool.
num_samples = duration_milliseconds * (sample_rate / 1000.0)
for x in range(int(num_samples)):
audio.append(volume * math.sin(2 * math.pi * freq * ( x / sample_rate )))
return
def save_wav(file_name):
# Open up a wav file
wav_file=wave.open(file_name,"w")
# wav params
nchannels = 1
sampwidth = 2
# 44100 is the industry standard sample rate - CD quality. If you need to
# save on file size you can adjust it downwards. The stanard for low quality
# is 8000 or 8kHz.
nframes = len(audio)
comptype = "NONE"
compname = "not compressed"
wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
# WAV files here are using short, 16 bit, signed integers for the
# sample size. So we multiply the floating point data we have by 32767, the
# maximum value for a short integer. NOTE: It is theortically possible to
# use the floating point -1.0 to 1.0 data directly in a WAV file but not
# obvious how to do that using the wave module in python.
for sample in audio:
wav_file.writeframes(struct.pack('h', int( sample * 32767.0 )))
wav_file.close()
return
append_sinewave(volume=1, freq=2350)
save_wav("output.wav")
不是真正的答案 - 更多的是问题。
您要求扬声器瞬间从静止波变为正弦波 - 这很难做到(尽管频率不是那么高)。如果它确实管理它,那么接收到的信号应该是大礼帽和正弦波的卷积(有点像你所看到的,但是没有一些数据并且不知道你在为频谱图做什么很难说).
在任何一种情况下,您都可以通过平滑音调的开始和结束来检查这一点。类似这样的音调生成:
tr = 0.05 # rise time, in seconds
tf = duration_milliseconds / 1000 # finish time of tone, in seconds
for x in range(int(num_samples)):
t = x / sample_rate # Time of sample in seconds
# Calculate a bump function
bump_function = 1
if 0 < t < tr: # go smoothly from 0 to 1 at the start of the tone
tp = 1 - t / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
elif tf - tr < t < tf: # go smoothly from 1 to 0 at the end of the tone
tp = 1 + (t - tf) / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
audio.append(volume * bump_function * math.sin(2 * math.pi * freq * t))
您可能需要稍微调整一下上升时间。使用这种形式的碰撞功能,您知道从开始后的 tr
到结束前的 tr
之间有一个完整的音量。存在许多其他功能,但如果这可以平滑频谱图中的 start/stop 效果,那么您至少知道它们为何存在。并且预防通常比尝试在 post-processing.
中消除影响更好。
我正在尝试检测录音中突然发出的巨响。我发现这样做的一种方法是创建音频的频谱图并添加每一列的值。通过绘制每列中值的总和,每次突然出现巨响时,都可以看到尖峰。问题是,在我的用例中,我需要在录制音频时播放蜂鸣音(频率为 2350 Hz)。蜂鸣声的频谱图如下所示:
如您所见,在这个蜂鸣声(这是一种频率为 2350 Hz 的简单音调)的开始和结束处,存在其他频率,但我未能成功去除。在对频谱图的列求和时,在蜂鸣声的开始和结束时,这些不需要的频率会导致尖峰。我想避免这种情况,因为我不想让我的哔哔声被检测为突然的巨响。请参阅下面的频谱图以供参考:
这是频谱图中每列总和的图形:
显然,我想避免在我的算法中出现误报。所以我需要一些方法来消除由哔哔声开始和结束引起的尖峰。到目前为止,我的一个想法是在上面的蜂鸣声谱图中的 2350 Hz 线以下添加具有高于 and/or 的低分贝值的随机噪声。理想情况下,这会创建一个听起来与原始音调非常相似的音调,但当我将列中的所有值相加时,它不会创建尖峰,而是会创建更多的平台。这个想法是解决我的问题的可行方法吗?如果是这样,我将如何使用 python 来创建具有随机噪声的蜂鸣声?对于我忽略的问题,还有其他更简单的解决方案吗?
目前,我正在使用以下代码生成提示音:
import math
import wave
import struct
audio = []
sample_rate = 44100.0
def append_sinewave(
freq=440.0,
duration_milliseconds=500,
volume=1.0):
"""
The sine wave generated here is the standard beep. If you want something
more aggresive you could try a square or saw tooth waveform. Though there
are some rather complicated issues with making high quality square and
sawtooth waves... which we won't address here :)
"""
global audio # using global variables isn't cool.
num_samples = duration_milliseconds * (sample_rate / 1000.0)
for x in range(int(num_samples)):
audio.append(volume * math.sin(2 * math.pi * freq * ( x / sample_rate )))
return
def save_wav(file_name):
# Open up a wav file
wav_file=wave.open(file_name,"w")
# wav params
nchannels = 1
sampwidth = 2
# 44100 is the industry standard sample rate - CD quality. If you need to
# save on file size you can adjust it downwards. The stanard for low quality
# is 8000 or 8kHz.
nframes = len(audio)
comptype = "NONE"
compname = "not compressed"
wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
# WAV files here are using short, 16 bit, signed integers for the
# sample size. So we multiply the floating point data we have by 32767, the
# maximum value for a short integer. NOTE: It is theortically possible to
# use the floating point -1.0 to 1.0 data directly in a WAV file but not
# obvious how to do that using the wave module in python.
for sample in audio:
wav_file.writeframes(struct.pack('h', int( sample * 32767.0 )))
wav_file.close()
return
append_sinewave(volume=1, freq=2350)
save_wav("output.wav")
不是真正的答案 - 更多的是问题。
您要求扬声器瞬间从静止波变为正弦波 - 这很难做到(尽管频率不是那么高)。如果它确实管理它,那么接收到的信号应该是大礼帽和正弦波的卷积(有点像你所看到的,但是没有一些数据并且不知道你在为频谱图做什么很难说).
在任何一种情况下,您都可以通过平滑音调的开始和结束来检查这一点。类似这样的音调生成:
tr = 0.05 # rise time, in seconds
tf = duration_milliseconds / 1000 # finish time of tone, in seconds
for x in range(int(num_samples)):
t = x / sample_rate # Time of sample in seconds
# Calculate a bump function
bump_function = 1
if 0 < t < tr: # go smoothly from 0 to 1 at the start of the tone
tp = 1 - t / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
elif tf - tr < t < tf: # go smoothly from 1 to 0 at the end of the tone
tp = 1 + (t - tf) / tr
bump_function = math.e * math.exp(1/(tp**2 - 1))
audio.append(volume * bump_function * math.sin(2 * math.pi * freq * t))
您可能需要稍微调整一下上升时间。使用这种形式的碰撞功能,您知道从开始后的 tr
到结束前的 tr
之间有一个完整的音量。存在许多其他功能,但如果这可以平滑频谱图中的 start/stop 效果,那么您至少知道它们为何存在。并且预防通常比尝试在 post-processing.