产生颤音正弦波

Generating vibrato sine wave

我正在尝试通过在两个 430Hz 和 450Hz 之间振荡来创建颤音,并将 16 位样本存储在列表 wav 中。然而,可听频率似乎增加了整个剪辑的振荡范围。有谁知道为什么?

编辑:重写代码以使其更加clear/concise

# 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

这个问题与伴随频率变化的隐含相位变化有关。简而言之,当您计算相对于时间轴中每个点的响应时,重要的是要注意振荡的相位对于每个频率在每个时间都是不同的(除了在它们都相同的起点)。因此,在频率之间移动就像在不同相位之间移动。对于在两个不同频率之间移动的情况,可以通过根据频率变化调整整体信号相位来针对 post hoc 进行校正。我已经解释过这个 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)