« AVRのUSARTでPCMオーディオ音が出た! | トップページ | Mega328の44.1khz非圧縮オーディオ再生 »

2009年1月16日 (金)

22khzステレオ8ビットのPCMオーディオ再生成功

まともな音にならない(1/13/09)
 SDカードからWAVファイルを読み込み、DACチップにCD音質の44.1khz16ビットステレオ音声を再生するプロジェクトは、Mega168の2つのSPI(ひとつはUSARTの同期シリアル)で、何とか音が出る段階まで進んだ。DACチップが始めて動いたのである。しかし、出てきた音は、かろうじて元の音とわかる程度の歪みだらけの音で、成功とは程遠いレベルであった。

 始めはアナログの部分のLPF(ローパスフィルター)がなかったり、ハイインピーダンス(10KΩ)出力にヘッドフォン(数Ω)をつけたからだと思っていたが、どうもそんなレベルの歪ではない。エミッタフォロワーのトランジスタをつけ、LPFらしきものをつけてみたが当然全く改善されない。どうもアナログ以前のデジタルに問題があるようだ。しかしデコードのタイミングチャートはロジアナで見た限りでは、全く問題がなく、ファイルもエラーなしで最後まで読みきっている。

 正弦波のデータを作って、再生してみれば何が原因で音が割れているのかわかると思うが、WAVファイルを、ライン入力から作るには、PCの裏側まで廻ってコードを接続したり、歪まないようレベルの心配をしたりするのが面倒で、何とかそこまでせずに解決できないかと、SPIのモードを変えてみたり、LRCKのタイミングを変えて見たり(データ送出終了割り込みでトグル)するが解決の気配はない。

 デジタルは大丈夫、タイミングチャートは完全とは言っても、ロジアナのデータは、トリガーとデータ蓄積量の制約で開始直後のところしかとれておらず、DAC書き出しとファイル読み込みが錯綜する部分のタイミングチャートは採集できていない。途中のデータをとるには、プログラムを組む必要があり、そう簡単には出来ない。

 そこで、オシロを持ち出して、サンプリングのタイミングを決めるLRCKだけでも表示させてみた。これが何と、不揃いなところが見つかったのである。11.3μsでなく、明らかに9μs近辺まで短くなっているところがある。こんなに大きくサンプリングが揺れれば当然、音は歪みまくる。これが原因か。しかしこれは有り得ない話だ。サンプリングの割込みを遅らせる要因になるタイマー割り込みはこのあいだマスクした。だとすると、割込み禁止の区間がSDカード読み込み処理の中にあることになる。これは調べるしかない。

 FatFSのソースを仔細に読んでいく。データを読む関数f_readは、PCM再生中動く唯一の関数で、これを掘り下げると、個々のクラスターを読むget_clusterになり、これは、mmc.cにあるディバイス依存の関数、disk_readに行く。そして、SDカードからデータを受け取るreadコマンドは、最終的にはすべてrcv_spiという1バイト読み込みの関数に行きつく。ここではSPIの割り込みは使わず、loop_until_bit_is_setというステートメントでループして待っている。CPUループで待っている。どこも割り込み禁止をしているところはない。とすると、どこが遅らせているのだろう。SPIを動かすと、CPUクロックまでが遅れる?まさか。

オシロの波形を一目見て原因が判明
(1/14/09)
 やっぱりまともに正弦波データを作って、ひとつづつ問題点を洗い出していくしか解決の道はなさそうだ。このあいだ作ったFG(ファンクションジェネレーター)の出番である。このFGの出力はいわゆる0デシベルのライン出力(1V  P-P)で、PCのサウンドボードのライン入力に直接つなげるはずだ。用心のため簡易アッテネーターを経由し、Windowsのサウンドレコーダーを始動させる。念のためオシロでも波形が見られるようにする。

 おお、出た出た。割れてもいないようだ。サウンドボードのライン入力は直接、出力にも出るので調整も楽だ。思ったより簡単に正弦波、方形波など各種の音声波形を入れたWAVファイルを作ることが出来た。ファイルをSDカードに移し、それをMega168に持ち込み、オシロをDAC出力につないで再生してみる。あっあっあー、なーんだ。わかった。出てきた波形を見て一発で原因がわかった。波形が途中から折れた正弦波が観測されたのである。方形波もいたるところで寸断されている。あれこれ悩む必要は何もなかった。最初から、波形データを調べれば良かったのである。音が途切れる原因はバッファーのアンダーランに違いない。ファイルの読み込みが間に合わず、DACのポインターが一周してしまっている。Dacovrflow

 サンプリング周期は変更できない(ジッターで音が歪む)ので、DACのデコードを待たせるわけには行かない。ファイルが読まれる前にDACへの送り出しのポインターが、読み込むべきバッファーの領域にまで入ってしまうと、新しいデータでなく前の古いデータをデコードすることになる。11.2μsごとに2バイトづつ送り出すDACのポインターが1周して、ダブルバッファーの2つを使い切る時間、11.33/2×160=906μs前の元の波形に戻っている波形がオシロに見事に表示されている。いやあ、素晴らしい。こんなにはっきり見えるとは。事態の深刻さも忘れて、暫し、オシロの威力に感動する。思い切って買っておいて良かった。

 SDカード読み込みの一回のサイズは、ダブルバッファーなので、全体の半分わずか80バイトしかない。これでもMega168のSRAMは80%以上の800バイトを越え、これ以上大きくすると、スタック領域に被ってプログラムがまともに動かなくなる。 バッファーのアンダーランは、始めは心配していたが、20Mhzのクロックだと、平均ではファイルアクセスの方が2倍以上早く、DACのオーバーヘッドもSPIにして20%以下になったのでつい油断していた。

 念のため、割込みルーチンにカウンターを設け、アンダーランしたとき(ファイルの読むバッファーと、取り出すバッファーが一致したとき)、カウントアップするステートメントを入れて調べてみた。結果は、べらぼうな数字で、1秒程度のWAVデータ(180KB)で、2万回は起きている。一旦、アンダーランが起きればファイルアクセスが止められるので、1ブロックをデコードする間すべてカウントされるから、バッファーサイズ80バイトとして40回、ダブルバッファーの切り替えは、180KBで、2250回、2万回/40=500回、2250/500=4~5回に1回は、ファイルアクセスが間に合わず追い越されている計算になる。

 少しでもアンダーランが減るかと、バッファーサイズを少しづつ増やしてテストしてみた。80バイトから128バイトまで増やすことができた(それ以上は暴走)。しかし、アンダーランの数は全く変わらない。厳密に言えば、新しいデータがバッファーに溜められたあとのアンダーランは必ずしもデータが間違っているわけではないので、回数のすべてが不正データと言うことではないが、いずれにしてもこの程度のバッファーサイズの増加は効果がないようだ。

 音の割れる原因は明らかになった。しかし、これは深刻な問題である。平均ではファイル読み込み速度の方が明らかにデコードより早いのでバッファーサイズを大きくすれば解決できるだろうが、Mega168というプラットホームに限定する限り、これ以上は無理である。オーバークロックという手もあるが、効果は余り期待できない。バッファーを5割増やしても変わらなかったのだから、2割程度のスピードアップで回避できるとは思えない。このあいだファイルアクセスルーチンを解析したときに、クラスターチェーンを延々と調べているロジックを見ている。読み始めると早いのだろうがアクセスは連続的ではない。

 最近、Mega328という168のフラッシュを32Kにした石が出てきて、これはSRAMが2Kある。これを使う手もあるが、ただ、2KのSRAMで間違いなくこの問題が解決されるかどうかはわからない。いずれにしても、SRAMが4KあるMega128ならともかく、残念ながらMega168では、CD音質の44.1khz16ビットステレオの再生は無理なようである。

念願の非圧縮PCMオーディオ(22khz)の再生に成功(1/16/09)
 プロジェクトの方向をどちらに進めるべきか迷った。SRAMの大きいMega128ないし、Mega328に換えて、あくまでもCD音質にこだわるか、44.1khzを諦め、22khzステレオ8ビットの非圧縮WAVデータの再生を考えるかである。というのは、昔、買った環境CDに入っていたクラシック音楽が22khzの8ビットデータにもかかわらず、なかなか良い音がしているのを見つけたからである。22khz8ビットステレオなら、データ量は1/4になり今のシステムでも十分再生可能の感じがする。

 実用的な用途を考えているわけではない。この程度のオーディオ機器なら今は市販の手のひらサイズのものがいくらでも手に入る(ICレコーダーがPCMで録音できる)。もとはといえば、はずみで買った16ビットDACチップを動かしてやろうと言う単純な動機である。とにかく音を出すほうが先だ。22khzステレオ8ビットデータの再生を試すことにする。

 プログラムの改修にとりかかる。サンプリングの周期を倍にする。デコードは16ビットDACなので、1バイトだけバッファーから読み、下位バイトは0にしてやれば8ビットデータが16ビットになる理屈である。あっというまに出来た。サウンドレコーダーで短い22khzステレオ8ビットWAVファイルを作り、はやる心を抑えながらブレッドボードの基板に持ち込む。

 再生してみる。あれえ、前よりひどい。ノイズでしかない。何を間違えたか。気を落ち着けてWAVフォーマットを確認する。ちゃんと書いてあった。16ビットデータと8ビットデータはフォーマットが違うのだ。16ビットは符号付き、8ビットは符号なしで、中間の128が0Vに相当する。やれやれ、あせってやるとろくなことはない。データから128を引いた変数を符号付き1バイトにキャストする。これで良いはずだ(自信がない)。

 今度こそと祈る気持ちで再生する。やったやった。とてもクリアな音がヘッドフォンから聞こえた。今までの音とは全く違う歪みのない音だ。テスト用の正弦波データを再生してみる。うむ、きれいな正弦波が出ている。間違いない。正しく再生できたようだ。

 勢いに乗って、20MBばかりの環境(ヒーリング)CDのクラシック曲をSDカードに移し、ヘッドフォン出力をPCスピーカーにつないで音をだしてみた。おお、全くノイズも歪みも感じられない美しい音だ。今までテストしてこなかった片チャンネルもついでに直結してみる。何だLPFをかけずに直結しても大して音は違わない。ステレオになったので余計音の厚みが増す。素晴らしい。PCの小さなスピーカーくらいでは、PCでの再生と違いは全くわからない。今まで歪みだらけの音を聞かされて暗い気持ちになっていた目の前の暗雲が吹き飛び、透き通った青空に雲雀の声を聞く気分である。今までの苦労がうそのようだ。A1151445

 嬉しくなって、7つばかりの曲データをすべてSDカードに入れて次々に再生する。いやあ22khz8ビットでもなかなかのものではないか。至福の時間である。これで去年の暮から始めた非圧縮オーディオの再生は、CDレベルには届かなかったが、とりあえず非圧縮PCMオーディオの再生まで辿りついた。曲を再生しながら、ブレッドボードに乗ったMega168、BU9480F、ファイルアクセスを示すLEDをいとおしく眺める。ジャングルのような配線を通して、この音が出ていると思うととても不思議な気分になる。

|

« AVRのUSARTでPCMオーディオ音が出た! | トップページ | Mega328の44.1khz非圧縮オーディオ再生 »

AVR」カテゴリの記事

コメント

私もMega328は買いました。まだ使っていませんが、重宝しそうです。

ただ、ライタソフトがMPU種類を知らない・・・

avrdudeならMega168指定で書けるようですが、フラッシュメモリのリミットは見ていないのかな・・・

投稿: そら。 | 2009年1月18日 (日) 08時37分

ありがとうございます。自作のFGの活躍の場を作りたくて、正弦波を作るソフトを探すところまで気が廻りませんでしたね。まあ成功したと言っても、22khz8ビットPCMは一昔前のPCサウンドカード程度なので、44khz16ビットのため、最近評判のMega328を発注しました。これならSRAMが2K
あるので、大丈夫なはずです。

投稿: がた老 | 2009年1月18日 (日) 01時54分

追伸

つぎはPCM録音ですかね? (^_^;)

投稿: そら。 | 2009年1月16日 (金) 21時37分

PCM再生おめでとうございます!!

正弦波などのWAVファイル作りですが、そういった単純な波形を作り出すソフトウェアは無かったのですか?

私はMacなのですが、Macでは正弦波やホワイトノイズなどを生成出来るフリーソフトがありました。

Windowsなら色々ありそうですが・・・

投稿: そら。 | 2009年1月16日 (金) 21時36分

コメントを書く



(ウェブ上には掲載しません)


コメントは記事投稿者が公開するまで表示されません。



トラックバック

この記事のトラックバックURL:
http://app.f.cocolog-nifty.com/t/trackback/1089557/27192583

この記事へのトラックバック一覧です: 22khzステレオ8ビットのPCMオーディオ再生成功:

« AVRのUSARTでPCMオーディオ音が出た! | トップページ | Mega328の44.1khz非圧縮オーディオ再生 »