MPD,FIFO,Python,Audioop,Arduino和Voltmeter:" Faking" VU表

时间:2014-02-13 18:21:04

标签: python audio fifo mpd

我正在尝试使用连接到Arduino(它本身连接到一些5V电压表)的计算机来“伪造”旧式立体声VU表。我的目标是让正在播放音频文件的计算机分析信号,并通过串行连接将振幅信息发送到Arudino,以显示在电压表上。

我正在使用MPD渲染音频并将其发送到USB DAC(ODAC)。 MPD也输出到FIFO,我使用Python脚本读取。我以4096字节的块读取FIFO,然后使用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)

1 个答案:

答案 0 :(得分:2)

回答我自己的问题。事实证明,无论我指定应该读取多少字节,os.read()返回2048字节。这意味着os.read()所采用的第二个参数是它将读取的最大字节数 - 但是并不能保证那么多字节实际< / em>被阅读。我曾经想过,当我打开FIFO时,os.read()调用将等待,直到它收到文件结束或指定的字节数,从而省略了NONBLOCK选项。但事实并非如此。为了解决这个问题,我的代码现在检查os.read()返回的字节字符串的长度,并且 - 如果该长度小于我指定的块大小 - 将等待获取下一个块然后将连接在继续处理数据之前,所有块都在一起,以便我有一个与我的目标匹配的块大小。