简体   繁体   English

产生颤音正弦波

[英]Generating vibrato sine wave

I'm trying to create a vibrato by oscillating between two 430Hz and 450Hz, storing the 16-bit sample in the list wav .我试图通过在两个 430Hz 和 450Hz 之间振荡来创建颤音,将 16 位样本存储在列表wav However, the audible frequency seems to increase range of oscillation across the entire clip.然而,可听频率似乎增加了整个剪辑的振荡范围。 Does anyone know why?有谁知道为什么?

edit: rewrote code to be more 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

-- ——

Update: because the response uses numpy, I'll update my code for plain python3更新:因为响应使用 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

The issue has to do with an implied phase change that goes along with changing the frequency.这个问题与随着频率变化而发生的隐含相位变化有关。 In short, when you calculate the response relative to each point in a timeline, it's important to note that the phase of the oscillation will be different for each frequency at each time (except at the starting point where they're all the same).简而言之,当您计算相对于时间轴中每个点的响应时,重要的是要注意每个频率的振荡相位在每个时间都会不同(除了在它们都相同的起点)。 Therefore, moving between frequencies is like moving between different phases.因此,在频率之间移动就像在不同相位之间移动。 For the case of moving between two distinct frequencies, this can be corrected for post hoc by adjusting the overall signal phases based on the frequency change.对于在两个不同频率之间移动的情况,这可以通过基于频率变化调整整体信号相位来进行事后校正。 I've explained this in another answer so won't explain it again here, but here just show the initial plot that highlights the problem, and how to fix the issue.我已经在另一个答案中解释了这一点所以不会在这里再次解释,但这里只显示突出问题的初始情节,以及如何解决问题。 Here, the main thing added is the importance of a good diagnostic plot, and the right plot for this is a spectrogram.在这里,添加的主要内容是良好诊断图的重要性,而正确的图是频谱图。

Here's an example:下面是一个例子:

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()

在此处输入图片说明

Note that the span of the frequency oscillation is increasing (as you initially heard).请注意,频率振荡的跨度正在增加(正如您最初听到的那样)。 Applying the correction linked to above gives:应用与上述链接的更正给出:

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)

在此处输入图片说明 Which is much closer to what was intended, I hope.我希望这更接近预期。

Another way to conceptualize this, which might make more sense in the context of looping through each time step (as the OP does), and as closer to the physical model, is to keep track of the phase at each step and determine the new amplitude considering both the amplitude and phase from the previous step, and combining these with the new frequency.对此概念化的另一种方法,在循环遍历每个时间步的上下文中可能更有意义(就像 OP 一样),并且更接近物理模型,是跟踪每个步的相位并确定新的幅度考虑上一步的幅度和相位,并将它们与新频率相结合。 I don't have the patience to let this run in pure Python, but in numpy the solution looks like this, and gives a similar result:我没有耐心让它在纯 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM