VolumioのLCDビューアーにビジュアライザをつけたい!一応完成
さてどうしよう。。。
前回、「もう少し考えて…」で終わった後、mpdやcavaの設定をいじったりしてみたんだけど、やっぱりこのためだけにプログラムもう1個別に動かすってのもちょっと僕の美学に反するなぁと(笑)。で、「cavaの中までいじることしない」と書いたものの、ちょっとソースを読ませてもらうと、まぁ要は波形データを読み込んでFFTして出力してるだけ(ってのは失礼ですが)っぽいので、それならその部分のプログラムをLCDビューアー内部に書くのそんなに難しくないんじゃないか?と、そっち方向で検討を進めることに。
つまり、cavaを省いてシンプルに。
FFTどうする?
FFTに関してはcavaでも使っている「FFTW」(https://www.fftw.org/)っていうCのライブラリがどうやらデファクトみたい。Rustでそいつに被せたラッパーライブラリ(https://docs.rs/fftw/latest/fftw/)もあるんだけど、でもなぁ、せっかくRustで書いてるんで、そこもPure Rustなライブラリ使う方がいいんじゃないかなぁ、FFTWをvolumioにインストールするのも苦労しそうだし。ってなことで、色々探していた結果、rustfft(https://docs.rs/rustfft/latest/rustfft/)とかmicrofft(https://crates.io/crates/microfft)など、いくつか発見。その中でももう少し抽象度の高い下記を見つけたので、こいつを使うことに決定。
https://crates.io/crates/spectrum-analyzer
これ内部でfftライブラリのmicrofftを使っているみたいでした。
信号処理とFFT
そもそも、フーリエ変換と向き合うのは、結構昔にJPEGエンコードアプリを書いていたとき以来、オーディオ信号に関してはズブのトーシロ。なんで、ネットの情報を色々と漁ってざっと勉強しなおして、人間の可聴範囲が~20kHzなんで、サンプリング定理により(懐かしい)CDのFQは44.1kHzなんだなぁとか今更ながらに知ったり、面白いんだが完全に理解もしとらんし。まぁ色々と確認しながら、振幅値を変換前と合わせるため結果をNで割らにゃいかんとか、周波数グラフは縦横対数軸にした方がいいのかとか。。。もう試行錯誤の繰り返し。
FIFOの読込
mpdから吐き出されるPCMデータのnamed PIPEを通した読込も本当は別スレッドに分けた方がいいのかもしれないんだけど、描画スレッドとの排他処理とか正直面倒なのと、却ってパフォーマンス悪くなる可能性もあり、1スレッドの中で処理。そうすると、曲が終わってmpdからFIFOに書き込みがないと読込でブロックして画面が止まっちゃったりするので、しかたなくCの標準低水準ライブラリのラッパーを使ってFIFOをO_NONBLOCKでopenし、readするように実装。ここは正直ださい(unsafe使いまくり)。で動かしてみると、あれぇ、なんかグラフの動きが曲と合ってないなぁ、スペクトルも変だし。あ、PCMの16bitデータだけど、振幅するから0~65535のu16ではなく、キャストして-32768~32767の符号付整数i16として扱わなきゃあかんのかぁ。
結果
ということでざっと作ってみました。cavaの場合は内部で周波数帯をbase, middle, trebleに分けて処理しているようなんだけど、まぁそこまでせんでもよいかな。。。もしくは、今回使ったspectrum-analyzerライブラリの中でやってくれちゃってたりするのかも。一応、いくつかの固定周波数のWAVで試して、まぁそれなりのスペクトルが確認できたので、そう間違ってるわけではないと思うんだけど、実際の曲になると、正直合ってるんだかどうかわからん。まぁ、別に解析用ではなく単なる飾りなんで、それっぽく動いているんで、まぁいいか(笑)。。。
ところで、音は? むむ、やっぱりたまにプツって途切れるんだけど、これは僕のプログラムというよりは、画面と音の時差を少なくするため、mpdの設定でスピーカー側に出力するALSAのバッファ長をデフォルトよりかなり小さくしたせいかな。。。こればっかりは方式上しかたないかなぁ。
ということで、起動パラメータでビジュアライザONにできるように下記をアップデートしておきました。(音飛びがどうしても気になる場合はmpdの設定はそのままで、ビジュアライザをONにしなけりゃいいので、たぶん。。。)
<2023/3/29 追記>
元々ビジュアライザの音ズレを少なくするためmpdのALSAバッファ長を小さくする設定にしていましたが、その辺りの設定を変更するのってあまり好きではないので、プログラムの方で解決しました。だが、音飛びは余計発生するように。。。バッファじゃなくて、FIFO読込のI/O辺りが原因なのかなぁ。。。
この記事が気に入ったらサポートをしてみませんか?