Попытка использовать классы «потокового» нижнего уровня python -sounddevice для воспроизведения и записи с массивами NumPy с ошибками - PullRequest
1 голос
/ 17 июня 2020

Я пытаюсь разбить аудиофайл на заданное количество NumPy блоков и поместить их в ОЗУ для воспроизведения, как и play_a_very_long_sound_file . К сожалению, мне не хватает знаний о массивах NumPy и аудиофайлах в целом. Как только этот код заработает, я хотел бы добавить процесс записи в функцию обратного вызова. С кодом, который у меня есть в настоящее время, я получаю:

ValueError: не удалось преобразовать строку в float: ''

, что происходит во втором 'if 'в функции обратного вызова. Я пытаюсь добавить нули в конец блока исходящих данных, но не знаю, как go об этом.

Еще одна любопытная вещь: я получаю только массив numpy, возвращенный из soundfile.read (), который обычно возвращает массив numpy и частоту дискретизации. Но я предполагаю, что это вызвано тем, что я разбил его на кадры. Любая помощь приветствуется!

def callback(outdata, frames, time, status):
  assert frames == args.blocksize
  if status.output_underflow:
    print('Output underflow: increase blocksize?', file=sys.stderr)
    raise sd.CallbackAbort
  assert not status
  try:
    data = q.get_nowait()
  except queue.Empty:
    print('Buffer is empty: increase buffersize?', file=sys.stderr)
    raise sd.CallbackAbort
  if len(data) < len(outdata):
    outdata[:len(data),0] = data
    outdata[len(data):,0] = b'\x00' * (len(outdata) - len(data))
    raise sd.CallbackStop
  else:
    outdata[:,0] = data


try:
  with sf.SoundFile(args.filename) as f:
    for _ in range(args.buffersize):
        data = f.read(frames=args.blocksize, dtype='float32')
        if data.size == 0:
            break
        q.put_nowait(data)  # Pre-fill queue
    stream = sd.OutputStream(  
        samplerate=f.samplerate, blocksize=args.blocksize,
        device=args.device, channels=f.channels, dtype='float32',
        callback=callback, finished_callback=event.set)
    with stream:
        timeout = args.blocksize * args.buffersize / f.samplerate
        while data.size != 0:
            data = f.read(args.blocksize, dtype='float32')
            q.put(data, timeout=timeout)
        event.wait()  # Wait until playback is finished
...