Python Librosa с микрофонным входом

Итак, я пытаюсь заставить librosa работать с микрофонным входом, а не просто с файлом wav, и у меня возникло несколько проблем. Сначала я использую библиотеку pyaudio для подключения к микрофону, но у меня возникают проблемы с переводом этих данных для использования librosa. Есть какие-нибудь предложения о том, как к этому подойти, или это вообще возможно?

Несколько вещей, которые я пробовал, включают получение данных от pyaudio mic, декодирование их в массив с плавающей запятой и передачу их в librosa (как видно из документации, это то, что librosa делает с wav-файлами с .load), но это не работает как выдает следующую ошибку: "librosa.util.exceptions.ParameterError: Аудиобуфер не является конечным везде"


FORMAT = pyaudio.paInt16
RATE = 44100
CHUNK = 2048
WIDTH = 2
CHANNELS = 2
RECORD_SECONDS = 5

stream = audio.open(format=FORMAT,
                    channels = CHANNELS,
                    rate = RATE,
                    input=True,
                    output=True,
                    frames_per_buffer=CHUNK)
while True:
        data = stream.read(CHUNK)
        data_float = np.fromstring(data , dtype=np.float16)
        data_np = np.array(data_float , dtype='d')
        # data in 1D array
        mfcc = librosa.feature.mfcc(data_np.flatten() , 44100)
        print(mfcc)


person Vince    schedule 26.11.2019    source источник
comment
Я не думаю, что это так просто, как вы думаете. Вы пытаетесь записывать и обрабатывать аудио в реальном времени!   -  person Ahmad Moussa    schedule 30.11.2019
comment
Привет, @AhmadMoussa, да, это определенно не так просто, как я сначала думал. Как будто я следил за этим на YouTube [youtube.com/watch?v=AShHJdSIxkY] для генерации синусоиды в реальном времени из микрофонного входа с помощью pyaudio, и мне было интересно, могу ли я сделать что-то подобное с librosa для сбора информации, такой как MFCC, в реальном времени, но я не знаю, достижимо ли это, или есть другой способ . Спасибо еще раз!   -  person Vince    schedule 02.12.2019


Ответы (1)


Вы можете сделать это с помощью функции callback из pyaudio. Я думаю, что проще использовать класс.

В конструкторе __init__ вы определяете всю необходимую константу и устанавливаете FORMAT на pyaudio.paFloat32, что позволит вам позже использовать его с librosa.

Затем методом start открываю аудиопоток. Параметры stream_callback в .open() позволяют указать способ реализации вашей функции.

callback метод принимает в качестве аргумента in_data, frame_count, time_info, flag, тогда вы получаете in_data в двоичных файлах. Поэтому вам нужно использовать np.frombuffer(in_data, dtype=np.float32), чтобы преобразовать их в массив numpy.

Как только это будет сделано, вы можете использовать свой numpy.ndarray, как обычно, с librosa.

Я думаю, что это можно оптимизировать, но это решение отлично работает для меня, надеюсь, что это поможет :)

import numpy as np
import pyaudio
import time
import librosa

class AudioHandler(object):
    def __init__(self):
        self.FORMAT = pyaudio.paFloat32
        self.CHANNELS = 1
        self.RATE = 44100
        self.CHUNK = 1024 * 2
        self.p = None
        self.stream = None

    def start(self):
        self.p = pyaudio.PyAudio()
        self.stream = self.p.open(format=self.FORMAT,
                                  channels=self.CHANNELS,
                                  rate=self.RATE,
                                  input=True,
                                  output=False,
                                  stream_callback=self.callback,
                                  frames_per_buffer=self.CHUNK)

    def stop(self):
        self.stream.close()
        self.p.terminate()

    def callback(self, in_data, frame_count, time_info, flag):
        numpy_array = np.frombuffer(in_data, dtype=np.float32)
        librosa.feature.mfcc(numpy_array)
        return None, pyaudio.paContinue

    def mainloop(self):
        while (self.stream.is_active()): # if using button you can set self.stream to 0 (self.stream = 0), otherwise you can use a stop condition
            time.sleep(2.0)


audio = AudioHandler()
audio.start()     # open the the stream
audio.mainloop()  # main operations with librosa
audio.stop()
person Ninii    schedule 17.06.2020
comment
Спасибо за ответ! Я попробую это сделать, способ, которым я работал, это запись в течение определенного времени (как только звук проходит заданную амплитуду), сохраните как файл wav, а затем используйте librosa, хотя мой обходной путь менее желателен. :) - person Vince; 22.06.2020