如何从PyAudio中的连接声音数据中删除弹出窗口

时间:2016-04-05 23:29:01

标签: python audio pyaudio

如何删除"弹出"和"点击"音频中的声音是通过将声音音调片段连接在一起构成的吗?

我有这个PyAudio代码用于生成一系列音调:

import time
import math
import pyaudio

class Beeper(object):

    def __init__(self, **kwargs):
        self.bitrate = kwargs.pop('bitrate', 16000)
        self.channels = kwargs.pop('channels', 1)
        self._p = pyaudio.PyAudio()
        self.stream = self._p.open(
            format = self._p.get_format_from_width(1), 
            channels = self.channels, 
            rate = self.bitrate, 
            output = True,
        )
        self._queue = []

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.stream.stop_stream()
        self.stream.close()

    def tone(self, frequency, length=1000, play=False, **kwargs):

        number_of_frames = int(self.bitrate * length/1000.)

        ##TODO:fix pops?
        g = get_generator()
        for x in xrange(number_of_frames):
            self._queue.append(chr(int(math.sin(x/((self.bitrate/float(frequency))/math.pi))*127+128)))

    def play(self):
        sound = ''.join(self._queue)
        self.stream.write(sound)
        time.sleep(0.1)

with Beeper(bitrate=88000, channels=2) as beeper:
    i = 0
    for f in xrange(1000, 800-1, int(round(-25/2.))):
        i += 1
        length = log(i+1) * 250/2./2.
        beeper.tone(frequency=f, length=length)
    beeper.play()

但是当音调发生变化时,会出现一个与众不同的音符#34;在音频中,我不知道如何删除它。

起初,我认为流行音正在发生,因为我正在播放每个片段,并且在生成片段时每次播放之间的时间足以导致音频变平。但是,当我将所有剪辑连接成一个字符串并播放时,流行音乐仍然存在。

然后,我认为正弦波在每个片段的边界处都不匹配,所以我尝试将当前音频片段的前N帧与前一片段的最后N帧进行平均,但是也没有效果。

我做错了什么?我该如何解决这个问题?

3 个答案:

答案 0 :(得分:2)

你为自己写的答案可以解决这个问题,但这并不是解决这类问题的正确方法。

其中一个问题是你检查"提示"或者通过与1进行比较来确定正弦波的峰值。并非所有正弦频率都会达到该值或者可能需要大量的周期来完成。

从数学上讲,对于K的所有整数值,正弦的峰值都是sin(pi / 2 + 2piK)。

要计算给定频率的正弦值,请使用公式y = sin(2pi * x * f0 / fs),其中x是样本数,f0是正弦频率,fs是采样率。

对于一个很好的数字,例如1kHz,48kHz采样率,当x = 12时:

sin(2pi * 12 * 1000/48000) = sin(2pi * 12/48) = sin(pi/2) = 1

然而,在997Hz的频率下,真正的峰值在样品12之后落后于样品的一小部分。

sin(2pi * 12 * 997/48000) = 0.99087178042
sin(2pi * 12 * 997/48000) = 0.99998889671
sin(2pi * 12 * 997/48000) = 0.99209828673

将波形拼接在一起的更好方法是从一种音调中跟踪相位,并将其作为下一种音调的起始相位。

首先,对于给定的频率,您需要计算出相位增量,请注意它与您使用样本分解的情况相同:

phInc = 2*pi*f0/fs

接下来,计算正弦并更新表示当前阶段的变量。

for x in xrange(number_of_frames):
    y = math.sin(self._phase);
    self._phase += phaseInc;

全部放在一起:

def tone(self, frequency, length=1000, play=False, **kwargs):

    number_of_frames = int(self.bitrate * length/1000.)
    phInc = 2*math.pi*frequency/self.bitrate

    for x in xrange(number_of_frames):
        y = math.sin(self._phase)
        _phase += phaseInc;
        self._queue.append(chr(int(y)))

答案 1 :(得分:1)

我最初怀疑个别波形没有对齐是正确的,我在Audacity中检查证实了这一点。我的解决方案是修改代码以启动和停止正弦波峰值上的每个波形。

def tone(self, frequency, length=1000, play=False, **kwargs):

    number_of_frames = int(self.bitrate * length/1000.)

    record = False
    x = 0
    y = 0
    while 1:
        x += 1
        v = math.sin(x/((self.bitrate/float(frequency))/math.pi))

        # Find where the sin tip starts.
        if round(v, 3) == +1:
            record = True

        if record:
            self._queue.append(chr(int(v*127+128)))
            y += 1
            if y > number_of_frames and round(v, 3) == +1:
                # Always end on the high tip of the sin wave to clips align.
                break

答案 2 :(得分:0)

如果要连接不同属性的剪辑,如果连接点处的两个剪辑的峰不对齐,则可能会听到咔嗒声。

解决此问题的一种方法是在第一个信号结束时执行Fade-out,然后在第二个信号开始时执行fade-in。然后通过其余的连接过程继续这种模式。有关Fading的详细信息,请Check here

我会在Audacity之类的可视化工具中尝试连接,在您要加入的剪辑上尝试Fade-outfade-in,并使用时间和设置来获得所需的结果。

接下来,我不确定pyAudio是否有任何简单的实施方式fading,但是,如果可以的话,您可能需要尝试pyDub。它提供了操作音频的简便方法。它同时包含Fade-inFade-out方法以及cross-fade方法,它们基本上只需一步执行淡入和淡出。

您可以将pydub安装为pip install pydub

以下是pyDub的示例代码:

from pydub import AudioSegment
from pydub.playback import play

#Load first audio segment
audio1 = AudioSegment.from_wav("SineWave_440Hz.wav")

#Load second audio segment
audio2 = AudioSegment.from_wav("SineWave_150Hz.wav")

# 1.5 second crossfade
combinedAudio= audio1.append(audio2, crossfade=1500)

#Play combined Audio
play(combinedAudio)

最后,如果您真的希望在专业级别上清除噪音/弹出,您可能需要查看PSOLAPitch Synchronous Overlap and Add)。 这里可以将音频信号转换为frequency domain,然后在块上执行PSOLA以合并音频,并尽可能降低噪音。

那很长,但希望它有所帮助。