Python PyAudio,输出有点卡顿。也许是数学

Python PyAudio, output little cracky. Maybe math

美好的一天。我有一个小问题,可能部分是数学问题。

问题是我想播放没有固定频率的正弦波。因此,为了不让过渡之间或固定频率期间的声音变得刺耳,我需要正弦波以零幅度开始和结束。从数学上讲,我明白必须做什么。

我选择了一种方法,我在其中调整 'time' 正弦波,以便它有时间完成所有周期。基本上 y=sin(2*pift) 其中 f*t 必须是整数。

问题是它确实有效但并不完全。所有的波最终都非常接近于零,但不完全在那里。改变频率时声音还可以,但并不完美。我不明白为什么最后一个元素不能落在零上。

如果你能仔细检查一下,我将非常感激。感谢

            import pyaudio
            import numpy as np
            import matplotlib.pyplot as plt

            p = pyaudio.PyAudio()
            volume = 0.5     # range [0.0, 1.0]
            fs = 44100*4       # sampling rate, Hz, must be integer
            time = 0.1  # in seconds, may be float
            f = 400        # sine frequency, Hz, may be float
            k = np.arange(int(time*fs))
            t=np.arange(0,time,1/fs)
            start=0
            end=time




            stream = p.open(format=pyaudio.paFloat32,
                            channels=1,
                            rate=fs,
                            output=True)



            # generate samples, note conversion to float32 array
            for i in range(1000):

                start = 0
                end = 40 / f #time to acomplish whole whole cycles according to the give frequency - must be whole number

                print(len(t))
                t = np.arange(start, end, 1 / fs)
                samples = (np.sin(2*np.pi*f*t)).astype(np.float32)

                print(samples[0],samples[-1]) # The main problem. I need first and last elements in the sample to be zero.
                                            # Problem is that last element is only close to zero, which make the sound not so smooth

                #print(start+i,end+i)
                #print(samples)  # # # # # Shows first and last element

                f+=1

                # for paFloat32 sample values must be in range [-1.0, 1.0]


            # play. May repeat with different volume values (if done interactively)
                stream.write(volume*samples)

            stream.stop_stream()
            stream.close()

            p.terminate()

正弦函数在 2*pi*N 的每个倍数处重复一次,其中 N 是整数。 IOW,sin(2*pi) == sin(2*pi*2) == sin(2*pi*3) 等等。

生成特定频率样本的典型方法是 sin(2*pi*i*freq/sampleRate),其中 i 是样本编号。

接下来是正弦只会在 i 的值处重复,这样 i*freq/sampleRate 正好等于一个整数(我不考虑相位偏移)。

最终结果是某些 frequency/sampleRate 组合可能仅在一个周期后重复 (1kHz @ 48kSr),而其他组合可能需要很长时间才能重复 (997Hz @ 48kSr)。

您不必为了避免毛刺而在精确的零交叉处更改频率。更好的方法是:

  1. 计算所需频率的相位增量为phaseInc = 2*pi*freq/sampleRate
  2. 对于每个输出样本,计算当前阶段的输出样本。 y = sin(phase)
  3. 通过相位增量更新相位:phase += phaseInc
  4. 重复 2-3 以获得所需数量的样本。
  5. 转到第一步更改频率

如果您坚持要在零交叉处改变,只需在最近的相位交叉 2*pi 的倍数的样本处进行。