【问题标题】:Generating vibrato sine wave产生颤音正弦波
【发布时间】:2015-01-28 05:25:45
【问题描述】:

我正在尝试通过在两个 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

【问题讨论】:

    标签: python audio python-3.x trigonometry


    【解决方案1】:

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

    【讨论】:

    • 为了清楚起见,我编辑了我的帖子。我使用 audacity 来查看波形,但这并没有真正的帮助,因为我们正在查看波形压缩的速率,而不是波形的实际值。我知道定义频率的初始正弦波工作正常,所以我认为这是一个概念问题。我对我的函数进行了导数,这表明我的样本函数改变了 Ω(t),所以我的函数不仅仅是正弦曲线。
    • @twinlakes:我明白你的意思了,我之前的回答是不正确的。我已经完全重写了,现在我认为它是正确的。
    猜你喜欢
    • 1970-01-01
    • 2011-07-25
    • 2020-05-03
    • 1970-01-01
    • 2012-01-08
    • 2016-08-17
    • 2012-01-27
    • 2011-07-03
    • 1970-01-01
    相关资源
    最近更新 更多