Python PyAudio,输出有点古怪。也许是数学

2024-04-26 20:34:02 发布

您现在位置:Python中文网/ 问答频道 /正文

再见。我有一个小问题,可能部分是数学问题。在

问题是我想玩没有固定频率的正弦波。因此,为了不使声音在转换之间或在固定频率期间爆裂,我需要正弦波开始和结束振幅为零。从数学上讲,我明白该做什么。在

我选择了一种方法,我调整了正弦波的“时间”,这样它就有时间完成所有的循环。其中整数必须是整数。在

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

如果你仔细检查一下,我会非常高兴的。泰铢

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

Tags: toinimportstreamtimenpbefs
1条回答
网友
1楼 · 发布于 2024-04-26 20:34:02

sine函数在2*pi*N的每一个倍数中重复自身,其中N是一个整数。低,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. 转到第一步以更改频率

如果你坚持在零交叉处改变,只需在最近的一个采样点进行,在那里相位与2*pi的倍数相交。在

相关问题 更多 >