Python 音频响应录音

Python 音频响应录音,python,user-interface,asynchronous,nonblocking,pyaudio,Python,User Interface,Asynchronous,Nonblocking,Pyaudio,我在PyAudio网站上看到了录制固定长度录音的教程,但我想知道如何在非固定录音中也能做到这一点?基本上,我想创建开始和结束录音的按钮,但我还没有找到任何相关的东西。有什么想法吗?我不是在寻找替代库?最好的方法是使用非阻塞的录制方式,即您提供一个回调函数,从启动流的那一刻起就被调用,并且在停止流之前,每个处理的块/缓冲区都会被调用 例如,在该回调函数中,检查布尔值,如果为true,则将传入缓冲区写入数据结构,如果为false,则忽略传入缓冲区。例如,可以通过单击按钮来设置此布尔值 编辑:查看wi

我在PyAudio网站上看到了录制固定长度录音的教程,但我想知道如何在非固定录音中也能做到这一点?基本上,我想创建开始和结束录音的按钮,但我还没有找到任何相关的东西。有什么想法吗?我不是在寻找替代库?

最好的方法是使用非阻塞的录制方式,即您提供一个回调函数,从启动流的那一刻起就被调用,并且在停止流之前,每个处理的块/缓冲区都会被调用

例如,在该回调函数中,检查布尔值,如果为true,则将传入缓冲区写入数据结构,如果为false,则忽略传入缓冲区。例如,可以通过单击按钮来设置此布尔值

编辑:查看wire audio的示例: 流是用一个参数打开的

stream_callback=my_callback
其中my_回调是一个声明为

def my_callback(in_data, frame_count, time_info, status)
每当有新的缓冲区可用时,就会调用此函数<代码>输入数据包含要记录的输入。在本例中,
In_data
pyaudio.paContinue
一起以元组形式返回。这意味着输入设备的输入缓冲区被放入/复制回输出设备发送的输出缓冲区(它是同一个设备,所以它实际上将输入路由到输出线)。有关更多说明,请参阅api文档:

因此,在这个函数中,您可以执行以下操作(这是从我编写的一些代码中提取的,但并不完整:我使用了一些未描述的函数。此外,我在一个通道上播放正弦波,在另一个通道上以24位格式播放噪波):

然后,您可以在流打开/运行时,从代码的另一部分将
record\u on
playback\u on
设置为
True
False
,从而在不中断流的情况下独立启动或停止录制和播放。 我将
in_data
复制到(threadsafe)
队列
中,另一个线程使用该队列写入那里的磁盘,否则队列将在一段时间后变大


顺便说一句:pyaudio是基于portaudio的,它有更多的文档和有用的提示。例如():回调函数必须在显示新缓冲区之前完成,否则缓冲区将丢失。因此,在回调函数中写入文件通常不是一个好主意。(虽然写入文件会被缓冲,我不知道它最终写入磁盘时是否会阻塞)

我不明白。你能进一步解释这个方法吗?我对C或C++不太熟悉。你真的能解释一些Python吗?这可能更简单吗?据我所知,不太简单。您可以使用非回调(阻塞)版本,但如果您不希望代码的其余部分冻结,则必须将其放在单独的线程中,这可能更复杂。回调版本也是与实时IO设备交互的标准方式。IO设备会导致操作系统/驱动程序中断,从而触发某些函数被调用(回调),对于最简单的情况,阻塞工作方式只是在此基础上构建的一种方便。这就是我用来模拟按钮按下的方式。见下文。

record_on = False
playback_on = False

recorded_frames = queue.Queue()

def callback_play_sine(in_data, frame_count, time_info, status):
    if record_on:
        global recorded_frames
        recorded_frames.put(in_data)

    if playback_on:
        left_channel_data = mysine.next_block(frame_count) * MAX_INT24 * gain
        right_channel_data = ((np.random.rand(frame_count) * 2) - 1) * MAX_INT24 * gain
        data = interleave_channels(max_nr_of_channels, (left_output_channel, left_channel_data), (right_output_channel, right_channel_data))
        data = convert_int32_to_24bit_bytestream(data)
    else:
        data = np.zeros(frame_count*max_nr_of_channels).tostring()

    if stop_callback:
        callback_flag = pyaudio.paComplete
    else:
        callback_flag = pyaudio.paContinue

    return data, callback_flag
import pyaudio
import wave

import pygame, sys
from pygame.locals import *

pygame.init()
scr = pygame.display.set_mode((640, 480))
recording = True

CHUNK = 1024
FORMAT = pyaudio.paInt16
CHANNELS = 2
RATE = 44100
RECORD_SECONDS = 5
WAVE_OUTPUT_FILENAME = "output.wav"

p = pyaudio.PyAudio()

stream = p.open(format=FORMAT,
                channels=CHANNELS,
                rate=RATE,
                input=True,
                frames_per_buffer=CHUNK)

print("* recording")

frames = []

while True:
    if recording:
        data = stream.read(CHUNK)
        frames.append(data)

    for event in pygame.event.get():
        if event.type == KEYDOWN and recording:
            print("* done recording")

            stream.stop_stream()
            stream.close()
            p.terminate()

            wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb')
            wf.setnchannels(CHANNELS)
            wf.setsampwidth(p.get_sample_size(FORMAT))
            wf.setframerate(RATE)
            wf.writeframes(b''.join(frames))
            wf.close()
            recording = False

        if event.type == QUIT:
            pygame.quit(); sys.exit()