Запись и воспроизведение звука через PyAudio

Введение

Звук в компьютере представляет собой последовательность значений амплитуды (громкости) реальной звуковой волны. Одно значение амплитуды в последовательности будем называть отсчетом (или фреймом).

Частота дискретизации - количество отсчетов на одну секунду записи (чем больше, тем выше качество). Стандартная частота дискретизации для CD - 44100.

Глубина звука - количество бит для хранения одного отсчета. Чем больше - тем точнее можно передать реальное значение амплитуды, а значит выше качество. Стандартное значение для CD - 16 бит (2 байта).

Количество каналов - количество звуковых дорожек внутри файла. В файле для стерео системы (т.е. обычной файле) на самом деле есть сразу две звуковые дорожки - для правого и левого динамика.

Поток - это буфер в памяти звукового устройства (записывающего или воспроизводящего), куда устройство времено складывает данные в ожидании момента, когда их заберет ваш скрипт.

CHUNK - количество отсчетов, которые будут считываться из потока за один раз.

Байт-строка - последовательность байт записанная в виде строки. Именно в таком виде данные будут считываться из потока.

Запись и воспроизведение звука с помощью PyAudio

import pyaudio

FORMAT = pyaudio.paInt16  # глубина звука = 16 бит = 2 байта
CHANNELS = 1  # моно
RATE = 48000  # частота дискретизации - кол-во фреймов в секунду
CHUNK = 4000  # кол-во фреймов за один "запрос" к микрофону - тк читаем по кусочкам
RECORD_SECONDS = 5  # длительность записи

# подключаемся к аудиокарте
audio = pyaudio.PyAudio()

# открываем поток для чтения данных с устройства записи по-умолчанию и задаем параметры
in_stream = audio.open(format=FORMAT, channels=CHANNELS,
                       rate=RATE, input=True,
                       frames_per_buffer=CHUNK)

# открываем поток для записи на устройство вывода - динамик - с такими же параметрами
out_stream = audio.open(format=FORMAT, channels=CHANNELS,
                        rate=RATE, output=True)
print("recording...")

audio_recording = b''  # пустая строка из байт

# для каждого "запроса"
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):  # RATE / CHUNK - кол-во запросов в секунду
    audio_recording += in_stream.read(CHUNK)  # читаем строку из байт длиной CHUNK * FORMAT = 4000*2 байт

print("finished recording")
print("now playing...")

# отправляем все что записали на колонки
out_stream.write(audio_recording)  # отправляем на динамик

# отключаемся от микрофона и динамика
out_stream.stop_stream()
out_stream.close()
in_stream.stop_stream()
in_stream.close()

# отключаемся от аудиокарты
audio.terminate()

Потоковая обработка звука с микрофона

В примере ниже мы используем библиотеку PyAudio чтобы получить доступ к микрофону и выводить на экран среднюю громкость звука за секунду.

import struct, pyaudio

FORMAT = pyaudio.paInt16  # глубина звука = 16 бит = 2 байта
CHANNELS = 1  # моно
RATE = 48000  # частота дискретизации - кол-во фреймов в секунду
CHUNK = 4000  # кол-во фреймов за один "запрос" к микрофону - тк читаем по кусочкам
RECORD_SECONDS = 20  # длительность записи

audio = pyaudio.PyAudio()

# открываем поток для чтения данных с устройства записи по умолчанию
# и задаем параметры
stream = audio.open(format=FORMAT, channels=CHANNELS,
                    rate=RATE, input=True,
                    frames_per_buffer=CHUNK)
print("recording...")

# каждую секунду
for i in range(RECORD_SECONDS):
    s = 0  # сумма отсчетов за секунду

    # для каждого "запроса"
    for j in range(RATE // CHUNK):  # RATE//CHUNK - количество "запросов" к микрофону в секунду
        data = stream.read(CHUNK)  # читаем строку из байт длиной CHUNK * FORMAT = 4000*2 байт

        # здесь мы превращаем байты в список из чисел, каждые два байта превращаются в число
        frames = struct.unpack("<" + str(CHUNK) + "h", data)  # строка -> список из CHUNK отсчетов, h - это short int

        # суммируем модули отсчетов - они могут быть отрицательными, поэтому убираем минус
        for frame in frames:
            s += abs(frame)

    print(s // RATE)  # выводим среднюю громкость секунды

print("finished recording")

Как записать звук в файл?

import pyaudio
import wave

# частока дискретизации и размер кусочка для считывания
FORMAT = pyaudio.paInt16
FRAMERATE = 44100
BUFFER = 4096
CHANNELS = 1  # моно

# открываем файл
music_file = wave.open("result2.wav", "wb")
music_file.setnchannels(CHANNELS)
music_file.setframerate(FRAMERATE)
music_file.setsampwidth(FORMAT)

# запрашиваем сигнал с микрофона
audio = pyaudio.PyAudio()
in_stream = audio.open(format=FORMAT, channels=CHANNELS,
                        rate=FRAMERATE, input=True, frames_per_buffer=BUFFER)

# длительность записи
seconds = 5

for i in range(seconds * FRAMERATE // BUFFER):
    data = in_stream.read(BUFFER)
    music_file.writeframes(data)
in_stream.stop_stream()

Как воспроизвести звук из файла?

import pyaudio
import wave

audio_file = wave.open("ИМЯ ФАЙЛА.wav")

FORMAT = audio_file.getsampwidth() # глубина звука
CHANNELS = audio_file.getnchannels() # количество каналов
RATE = audio_file.getframerate() # частота дискретизации
N_FRAMES = audio_file.getnframes() # кол-во отсчетов
audio = pyaudio.PyAudio()

# открываем поток для записи на устройство вывода - динамик - с такими же параметрами
out_stream = audio.open(format=FORMAT, channels=CHANNELS,
                        rate=RATE, output=True)

out_stream.write(audio_file.readframes(N_FRAMES))  # отправляем на динамик

audio.terminate()