Я пытаюсь использовать компьютер, подключенный к Arduino (который сам подключен к некоторым 5-вольтовым вольтметрам), чтобы «подделать» старый школьный стереометр VU. Моя цель состоит в том, чтобы компьютер, который воспроизводит аудиофайл, анализировал сигнал и отправлял информацию об амплитуде в Arudino через последовательное соединение для отображения на вольтметрах.
Я использую MPD для рендеринга и отправки звука на USB-ЦАП (ODAC). MPD также выводит в FIFO, который я прочитал с помощью скрипта Python. Я читаю из FIFO фрагментами по 4096 байт, затем использую библиотеку audioop, чтобы разделить этот фрагмент/сэмпл на левый и правый канал и вычислить максимальную амплитуду каждого канала.
Вот проблема - я завален данными. Я предполагаю, что моя математика неверна или я не понимаю, как работает FIFO (или, может быть, и то, и другое). MPD выводит все в формате 44100:16:2 — я думал, что это означает, что он будет записывать 44 100 4-байтовых выборок в секунду. Поэтому, если я захватываю фрагменты по 4096 байт, я должен ожидать около 43 фрагментов в секунду. Но я получаю гораздо больше (более 100), и количество фрагментов, которые я получаю в секунду, не меняется, если я увеличиваю размер фрагмента. Например, если я удвою размер блока до 8192, я все равно буду получать примерно такое же количество блоков в секунду. Так что я явно делаю что-то не так, но я не знаю, что это такое. У кого-нибудь есть мысли?
Вот соответствующая часть моего файла mpd.conf:
audio_output {
type "fifo"
name "my_fifo"
path "/tmp/mpd.fifo"
format "44100:16:2"
}
А вот и Python-скрипт:
import os
import audioop
import time
import errno
import math
#Open the FIFO that MPD has created for us
#This represents the sample (44100:16:2) that MPD is currently "playing"
fifo = os.open('/tmp/mpd.fifo', os.O_RDONLY)
while 1:
try:
rawStream = os.read(fifo, 4096)
except OSError as err:
if err.errno == errno.EAGAIN or err.errno == errno.EWOULDBLOCK:
rawStream = None
else:
raise
if rawStream:
leftChannel = audioop.tomono(rawStream, 2, 1, 0)
rightChannel = audioop.tomono(rawStream, 2, 0, 1)
stereoPeak = audioop.max(rawStream, 2)
leftPeak = audioop.max(leftChannel, 2)
rightPeak = audioop.max(rightChannel, 2)
leftDB = 20 * math.log10(leftPeak) -74
rightDB = 20 * math.log10(rightPeak) -74
print(rightPeak, leftPeak, rightDB, leftDB)