在Python中使用麦克风录音时,删除系统声音输出

时间:2018-07-22 15:56:57

标签: python audio audio-recording microphone pyaudio

实际上,我正在用麦克风录制所有声音,并且我想过滤输入以删除系统声音输出,例如在播放音乐时清楚地了解用户的声音(例如Skype所做的事情)。< / p>

我正在寻找一个Python模块,该模块可以在Ubuntu 16.04中执行此操作,或者至少可以记录系统输出的内容。

这是我的脚本(我正在使用Pyaudio):

THRESHOLD = 1500
CHUNK_SIZE = 1024
FORMAT = pyaudio.paInt16
RATE = 44100
MAX_RECORDING_TIME = 7 # seconds
MAX_SILENCE_UNITS = 65

def is_silent(snd_data):
    "Returns 'True' if below the 'silent' threshold"
    return max(snd_data) < THRESHOLD

def normalize(snd_data):
    "Average the volume out"
    MAXIMUM = 16384
    times = float(MAXIMUM)/max(abs(i) for i in snd_data)
    r = array('h')
    for i in snd_data:
        r.append(int(i*times))
    return r

def record():
    """
    Record a word or words from the microphone and 
    return the data as an array of signed shorts.
    Normalizes the audio.

    the recording stops after 7 seconds or a sequence of 65 silent recording units
    """
    p = pyaudio.PyAudio()
    stream = p.open(format=FORMAT, channels=1, rate=RATE,
        input=True, output=False,
        frames_per_buffer=CHUNK_SIZE)

    num_silent = 0
    snd_started = False

    r = array('h')

    begin_time = 0
    while 1:
        # little endian, signed short
        snd_data = array('h', stream.read(CHUNK_SIZE))
        if byteorder == 'big':
            snd_data.byteswap()

        if (snd_started):
            r.extend(snd_data)

        silent = is_silent(snd_data)

        if silent and snd_started: # we compute the number of silent units
            num_silent += 1
        elif not silent and not snd_started:
            print("start recording !")
            snd_started = True
            begin_time = time.time() # we save the current time
        if not silent:
            num_silent = 0

        now = int(time.time())
        if snd_started and (now-begin_time>MAX_RECORDING_TIME or num_silent > MAX_SILENCE_UNITS):
            break

    print("recording finished !")

    sample_width = p.get_sample_size(FORMAT)
    stream.stop_stream()
    stream.close()
    p.terminate()

    r = normalize(r)
    return sample_width, r

def record_to_file(path):
    "Records from the microphone and outputs the resulting data to 'path'"
    sample_width, data = record()
    data = pack('<' + ('h'*len(data)), *data)

    wf = wave.open(path, 'wb')
    wf.setnchannels(1)
    wf.setsampwidth(sample_width)
    wf.setframerate(RATE)
    wf.writeframes(data)
    wf.close()

1 个答案:

答案 0 :(得分:1)

要完全删除语音记录中的声音输出(通常没有最佳条件,例如在嘈杂环境中的台式麦克风),很难做到很好,尽管想到了最简单的一种,但滤波技术很多。

删除系统输出的直接声音

要获得音频系统的输出,您将需要使用某种loopback device,可能使用PulseAudio。这样,您可以打开2个输入音频流,并且能够同时接收您的麦克风数据和系统输出数据(这将像您目前使用的阻塞方法一样工作,但是如果您换成回调,我会很警惕)

那么,最简​​单的方法是从麦克风接收的音频块中减去系统音频输出音频块中的所有值。假设没有真正的延迟问题,那么这将从麦克风录音中删除所有从设备发出的直接声音。

伪代码:

output = microphone_audioBlock - systemOutput_audioBlock 

您需要考虑以下几点:

  • 您需要检查是否使用了耳机,这样您就不会再减去声音了
  • 这不会消除所有间接声音(即房间中产生的混响/反射)

此方法很简单,但是正如我提到的那样,它不会消除间接声音。消除间接声音的方法很多,但都是一般的研究概念。

减少背景噪音

除此之外,您可能希望减少背景噪音;在DSP术语中,这称为noise suppression

由于您只能使用一个麦克风,并且无法很好地控制定位(很可能是这样),因此如果没有某种DSP算法实现,就没有直接的方法来实现。我在以下几个地方附加了您可以阅读的有源噪声抑制技术: