我试图通过在两个430Hz和450Hz之间振荡来创建颤音,并将16位样本存储在列表wav
中。但是,可听频率似乎增加了整个剪辑的振荡范围。有人知道为什么吗?
编辑:重写代码以使其更清晰/简洁
# vibrato.py
maxamp = 2**15 - 1 # max signed short
wav = []
(t, dt) = (0, 1 / 44100)
while t < 6.0:
f = 440 + 10 * math.sin(2 * math.pi * 6 * t)
samp = maxamp * math.sin(2 * math.pi * f * t)
wav.append(samp)
t += dt
-
更新:因为响应使用numpy,所以我将更新纯Python3的代码
# vibrato.py
maxamp = 2**15 - 1 # max signed short
wav = []
(t, dt) = (0, 1 / 44100)
phase = 0
while t < 6.0:
f = 440 + 10 * math.sin(2 * math.pi * 6 * t)
phase += 2 * math.pi * f * t
samp = maxamp * math.sin(phase)
wav.append(samp)
t += dt
最佳答案
这个问题与隐含的相位变化以及频率变化有关。简而言之,当您计算相对于时间线中每个点的响应时,请务必注意,振荡的相位对于每个频率在每个时间都会有所不同(除了起点都相同)。因此,在频率之间移动就像在不同相位之间移动一样。对于在两个不同频率之间移动的情况,可以通过基于频率变化来调整整个信号相位来进行事后校正。我已经解释了此in another answer,因此在这里不再赘述,而在这里仅显示突出显示问题的初始图解以及如何解决问题。在这里,主要要添加的是一个好的诊断图的重要性,而正确的图就是一个频谱图。
这是一个例子:
import numpy as np
dt = 1./44100
time = np.arange(0., 6., dt)
frequency = 440. - 10*np.sin(2*math.pi*time*1.) # a 1Hz oscillation
waveform = np.sin(2*math.pi*time*frequency)
Pxx, freqs, bins, im = plt.specgram(waveform, NFFT=4*1024, Fs=44100, noverlap=90, cmap=plt.cm.gist_heat)
plt.show()
请注意,频率振荡的跨度正在增加(如您最初听到的)。应用上面链接的更正将得出:
dt = 1./defaults['framerate']
time = np.arange(0., 6., dt)
frequency = 440. - 10*np.sin(2*math.pi*time*1.) # a 1Hz oscillation
phase_correction = np.add.accumulate(time*np.concatenate((np.zeros(1), 2*np.pi*(frequency[:-1]-frequency[1:]))))
waveform = np.sin(2*math.pi*time*frequency + phase_correction)
我希望这更接近预期的目标。
对此进行概念化的另一种方法,可能是在遍历每个时间步长的上下文中(如OP所做的那样),并且与物理模型更接近,这可能是在每个步长跟踪相位并确定新的幅度考虑上一步的幅度和相位,并将其与新频率组合。我没有耐心让它在纯Python中运行,但是在numpy中,解决方案看起来像这样,并给出了类似的结果:
dt = 1./44100
time = np.arange(0., 6., dt)
f = 440. - 10*np.sin(2*math.pi*time*1.) # a 1Hz oscillation
delta_phase = 2 * math.pi * f * dt
phase = np.cumsum(delta_phase) # add up the phase differences along timeline (same as np.add.accumulate)
wav = np.sin(phase)
关于python - 产生颤音正弦波,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28185219/