2

古い学校のステレオVUメーターを「偽造」するために、Arduino(それ自体が5Vの電圧計に接続されている)に接続されたコンピューターを使用しようとしています。私の目標は、オーディオ ファイルを再生しているコンピューターで信号を分析し、振幅情報をシリアル接続を介して Arudino に送信し、電圧計に表示させることです。

MPD を使用してオーディオをレンダリングし、USB DAC (ODAC) に送信しています。MPD は、Python スクリプトを使用して読み取った FIFO にも出力しています。FIFO から 4096 バイトのチャンクで読み取り、audioop ライブラリを使用してそのチャンク/サンプルを左右のチャネルに分割し、各チャネルの最大振幅を計算します。

ここに問題があります。私はデータに圧倒されています。私の計算が間違っているか、FIFO がどのように機能するか (あるいはその両方) を理解していないのではないかと推測しています。MPD はすべてを 44100:16:2 形式で出力しています。これは、1 秒あたり 44,100 の 4 バイト サンプルを書き出すことを意味していると思いました。したがって、4096 バイトのチャンクを取得する場合、1 秒あたり約 43 チャンクを期待する必要があります。しかし、私はそれよりもはるかに多く (100 以上) 取得しており、チャンク サイズを大きくしても、1 秒あたりに取得するチャンクの数は変わりません。たとえば、チャンク サイズを 2 倍の 8192 にしても、1 秒あたりのチャンク数はほぼ同じです。明らかに私は何か間違ったことをしていますが、それが何であるかはわかりません。誰にも考えはありますか?

私の 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)
4

1 に答える 1

2

私自身の質問に答えます。読み込む必要があると指定したバイト数に関係なく、os.read() は 2048 バイトを返していることがわかりました。つまり、 os.read() が取る 2 番目のパラメーターは、読み取る最大バイト数ですが、その多くのバイトが実際に読み取られるという保証はありません。読まれます。FIFO を開いたときに NONBLOCK オプションを省略すると、ファイルの終わりまたは指定されたバイト数を受け取るまで os.read() 呼び出しが待機するのではないかと考えていました。しかし、そうではありません。この問題を回避するために、私のコードは os.read() によって返されたバイト文字列の長さをチェックし、その長さが指定したチャンク サイズよりも小さい場合は、次のチャンクを取得するのを待ってから連結します。すべてのチャンクをまとめて、データの処理に移る前にターゲットに一致するチャンク サイズを確保します。

于 2014-02-20T19:15:12.233 に答える