Python PyAudio,输出有点破解。也许数学

时间:2016-09-02 09:46:23

标签: python audio wave pyaudio sine

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

事情是我想在没有固定频率的情况下播放正弦波。因此,不要在转换之间或在固定频率期间使声音破裂,我需要正弦波开始并以幅度零结束。在数学上我理解必须做什么。

我选择了一种方式,在那里我调整了正弦波的“时间”,因此它有时间完成所有周期。基本上y = sin(2 * pi f t)其中f * t必须是整数。

问题是它实际上有效但不完全。所有波浪最终都接近于零,但并非完全存在。在改变频率但不完美的情况下声音很好。我无法弄清楚为什么最后一个元素不能归零。

如果你想通过它并检查我真的很棒。 THX

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

1 个答案:

答案 0 :(得分:1)

正弦函数在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完全等于整数(我忽略相位偏移)。

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

没有必要在准确的过零点处更改频率以避免毛刺。更好的方法是:

  1. 将所需频率的相位增量计算为phaseInc = 2*pi*freq/sampleRate
  2. 对于每个输出样本,计算当前阶段的输出样本。 y = sin(phase)
  3. 按阶段增量更新阶段:phase += phaseInc
  4. 对所需数量的样本重复2-3次。
  5. 转到第一步更改频率
  6. 如果您坚持在零交叉处进行更改,只需在相位超过2 * pi倍数的最近样本处进行。