コグノスケ


2014年 7月 9日

alsa-lib dmix のバグ

目次: ALSA - まとめリンク

ALSA のライブラリ alsa-lib(Git リポジトリ)のミキシングプラグイン dmix のバグらしきものを見つけたのでメモ書きを残しておきます。

現象

簡単に言えば dmix プラグインのミキシング音声に激しいノイズが載ります。発生条件はわかっている限りで、下記の通りです。

  • dmix プラグインを用いてミキシングを行う、つまり 2つ以上の音声を出力する。
  • PC 以外(つまり x86 や x64 以外)の CPU 向けにビルドされた alsa-lib を用いる、例えば Debian armel 向けパッケージなど。
  • CPU のエンディアンと異なる(CPU がリトルなら、サウンドカードはビッグ)エンディアンの LPCM を受け取るサウンドカードに対し音声を出力する、例えば S32_BE など。

現象は条件を満たせば必ず発生するようです。

バージョンは 1.0.27.2(2013年 7月 8日リリース)で発生しますが、おそらくその前、後のバージョンでも発生します。

詳細は後述しますが、原因となる箇所を見る限り Git リポジトリの HEAD でも特に解決されている様子はありません。調べたリビジョンへのリンク

原因

おそらくですが、CPU のエンディアンと異なるエンディアンの LPCM をミキシングするための汎用関数 generic_mix_areas_32_swap() が、符号の扱いを間違っているためです。

問題の箇所は下記の通りです。ソースファイル名は alsa-lib/src/pcm/pcm_dmix_generic.c です。

alsa-lib の汎用ミキシング関数に至るまで

snd_pcm_mmap_writei()
    snd_pcm_write_areas()
        func = snd_pcm_mmap_write_areas()
            snd_pcm_mmap_commit()
                pcm->fast_ops->mmap_commit() = snd_pcm_dmix_mmap_commit()
                    snd_pcm_dmix_mmap_commit()
                        snd_pcm_dmix_sync_area()
                            mix_areas()
                                generic_mix_areas_32_swap() //★★これ★★

(関数ポインタの設定箇所など)

generic_mix_select_callbacks()
    dmix->u.dmix.mix_areas_32 = generic_mix_areas_32_swap()

この generic_mix_areas_32_swap() 関数の 4行目にある、
sample = bswap_32(*src) >> 8;
が、おそらく意図と異なる結果を招いています。

意図する処理は 1/256 のスケーリングだと思いますので、
sample = (signed int)bswap_32(*src) >> 8;
が正しいと思われます。

解説

何がまずいかというと bswap_32() の返り値の型が unsigned int のため、右シフト(>> 8)が符号を無視してシフトしてしまうことです。

何故まずいか?というと bswap_32() が(符号付きの値としてみたとき)負の値を返したときに、意図せず結果が正の値になってしまい、音が変わってしまう、という問題を招くからです。

例を出した方がわかりやすいと思います。

例えば、bswap_32() が 0xffffec78 を返したとします。これは符号付きの値としてみると負の値 -5000 です。

本来の右 8ビットシフトの期待値は上位ビットを 1 で埋めた -20(0xffffffec)を得ることだと思われます。しかし、現在の alsa-lib のコードだと上位ビットを 0 で埋めてしまうため、結果が 16777196(0x00ffffec)と全く違う値になり、ノイズの発生源となってしまいます。

編集者: すずき(更新: 2022年 5月 22日 15:15)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2014年 7月 24日

国家を一か八かの勝負に使わないで欲しい

「軍事的な抑止力」なんて時代遅れ、憲法9条こそが抑止力だと思います(1)を読んで。

私は、病気になるかも知れないから保険に入ろう、そのためのコストは払おうと思うけど、

このサイトの筆者さんのように、病気にならないように過ごせば保険は不要、自分のやりたいことに使おう、という考えもあるんだなあ。

でも病気になったら諦める以外ないから、ギャンブラーですよね。いずれにせよハイリスクハイリターン志向ですね。

メモ: 技術系の話は Facebook から転記しておくことにした。

編集者: すずき(更新: 2015年 11月 29日 19:52)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2014年 7月 26日

Java の abstract はどこに書く?

Java の修飾子(Modifiers)は、どの順で書くのが正解あるいは推奨なのでしょうか?Java の修飾子は適当な順に書いてもエラーにならないため、私は今まで何も気にせずに書いていたのですが、不思議なことに一度気にし始めたら気になって仕方ありません。

ググって見ると abstract public と書く人が多い(デー - public、abstract、static、finalなど修飾子の順番 (3)より)そうです。自身の今まで書いたコードを見直しても、abstract public と書くことが多かったため、特に意識せず書くとこんな順になるんだろうか、と思ったりしていたのですが…。

Java 言語仕様 3版を見ると public abstract が例として出ているではありませんか。どうやら仕様策定した人としては public abstract と書いて欲しいようです。

なお、コード例は 8.4.3.1 abstract Methods にあります。

編集者: すずき(更新: 2014年 7月 26日 23:31)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2014年 7月 27日

いつものパターン

すげえ数売れて超儲かるお花畑計画が承認され、多額の予算と人材が投入され、不発に終わり超絶赤字を叩き出す、までがテンプレになっている。

でも一度も「今回は失敗だった、何故か考えよう」という会議を見たことがありません。

実はやっていたとしても、こう何度も同じ失敗ばかりでは、何も学べていないも同然なので根底を変えるべきでしょうし、失敗は恥ずかしいからと、誤魔化したり、自然消滅させているならさらに悪いでしょう。学習能力ゼロです。

組織も生き物も、学習能力のないやつは早々に死にます。ヤバいわこれ…。

メモ: 技術系の話は Facebook から転記しておくことにした。

編集者: すずき(更新: 2015年 11月 29日 19:55)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報