LCDをつけた実装版PCMプレーヤーの設計
LCDにリスト表示する検討に入る(1/27/09)
サンプリング周波数44.1khzの音楽CDの非圧縮(リニアー)PCMの再生に成功して少し気が抜けた。ブレッドボードはロジアナのプローブケーブルも加えてうず高い配線の山がボードの2/3を占めている。このまましておくわけにもいかない。といって、これを解体すれば今までの苦労の成果は消えてなくなる。まあ消えるわけではないが、もう一度作り直すのは大変だ。
となると、やっぱり実装して残すしかない。そういえば、このあいだ携帯のリチウムバッテリーの実験をして、バッテリーの使い途を考えていたところである。バッテリーをこの試作版につけて動かし、消費電流を測ってみた。待機のときが30mA、再生時は60mA程度だった。バッテリーの容量は830mAh、連続再生でも10時間は持つ。うむ、これを電池に小さいPCMプレーヤーを作ってやろうか。少し制作意欲がでてきた。
レイアウトしてみる。LCDは秋月の超小型と称する16 字2 行のものが、何かのときにと思って買ってある(¥800)。バックライトがついているが、なくても視認性は悪くない。電池やLCDが小さいので、DIP版のMega328に、LCDをつけても、かなり薄く、定期入れサイズくらいに小型化できそうである。
これくらいなら市販のプレーヤーと並べて恥ずかしくなるほど大きくはなるまい。こちらは何と言ってもMP3などと違うリニアーの非圧縮オーディオなのだ。格が違う。SDカードソケットをマイクロSD用のものに換えればもっと小さくできる。よーし、これに決めた。
プロジェクトの方向が見えたので、以前の記事(12/27/08)の計画で、(3)LCDで操作を考える段階に入った。今度はそう簡単ではない。表示をUARTからLCDに換えるだけではない。入力ディバイスも必然的にタクトスイッチなどにしなければならない。しかも表示はたったの2行である。これでSDカードに入っている沢山のWAVファイルを表示させて選択し、再生の指示をしなければならない。好い加減な設計では、あとで苦労することが見えている。
とは言え、フラッシュサイズはふんだんにある。16KBでも十分なのに32KBもある。連続再生や、ランダム再生、経過時間表示など考えられることは大抵実装できるだろう。しかし、表示が2行32文字しかないのが一番の難関である。余り機能を盛り込みすぎると、昔買った、S○○yのHIMDレコーダーのように、使い物にならない操作性になってしまう。
課題はやはり、わずか2行の表示スペース内で再生するたくさんのファイル名をいかにわかりやすく表示するかである。SDカードに入っているWAVファイルの数に制限は作りたくない。限られたSRAMスペースに、SDカードの全部のファイル名をどうやって収容するか、タクトスイッチによる上下のスクロールをいかにスムーズに行うか。スイッチの機能をいかに整理して操作しやすくするか。これは完全にロジックの世界である。久しぶりのソフト開発に腕が鳴る。段々気分が盛り上がってきた(それにしても安い娯楽だ)。
擬似コーディング(ソースコードを自然語で書いていく方法)で、簡単に出来上がる規模ではない。メモリ上に一部だけ読んだディレクトリのファイル名リストを作り、タクトスイッチに応じて表示する行を上下させる必要がある。メモリは無限にとれないので、リストの最後に来れば次のファイル名をディレクトリから読み取りディレクトリの最後までこれを繰り返す必要がある。少しづつディレクトリを読み取ることで、無限のディレクトリに対応できるが、ファイル名をスクロールさせようとすると、処理は急に複雑になり、垂れ流しのUARTのように単純には行かない。簡単な機能を作りこれを発展させていく方法では無理である。
オブジェクト指向的設計の出番である。これは私が勝手に名をつけている方法で、オブジェクト指向的というように、オブジェクト指向のコンセプトを使った全体設計手法である。機能をオブジェクトとして分割し、その間を最初は抽象的なメッセージ(データを貰う、ボタンを押すなど)でつなぎ、全体の動作を確認した後、オブジェクトを関数などに置き換えていく。こうしておくと機能が独立し、このあとの設計が格段に楽になる。
オブジェクト指向というと、機能継承とか多態性とかクラス、インヘリタンスなどの専門用語が飛び交う何か異次元のプログラミングと思われがちだが、コンセプトそのものは、実は30年も前から汎用機やUNIXなどのOSの開発ではごく当たり前の開発手法だったように思う。
開発したコードの寿命を長くして結果として全体の開発コストを下げるには、機能に絞り、なるべく他と影響がない丈夫なコードを作っていく必要がある。それには自分の中の情報は外にださず、他との関係をなるべく抽象的にしておくのが良い(カプセル化でデータまで入れてしまえば本当のオブジェクト指向に近づく)。
その意味では、C言語は実は使いにくい。内部関数を作れないからだ。関数は全部外に見えてしまう。従って、外に出したくない変数も全部、外部変数にしなければならない。昔私が使っていたPASCALはその点、内部関数が階層的にいくらでも定義でき、情報を隠蔽化するのに苦労しなかった。Cはその点とても気を遣う。内部の繰り返し処理のために気楽に関数を作れない。変数を全部、引数にするか、外部変数を使わないといけない。
昔話はさておき、開発に戻ろう。今度のLCDへの表示機能をまとめる。タクトスイッチは、ファミコンのように上下の移動ボタンと、決定ボタンの3つで決まりだ。全体をいくつかの機能に分割し、それぞれがメッセージに基づいて動くように、何枚もメモに機能図を書き散らして、おおよその構成を作っていった。
その結果、機能は、
A「ディレクトリを命じられたところから一定数読み出しメモリに入れる」ブロック
B「そのメモリにあるディレクトリから、指示に基づき一部をLCDに表示する」ブロック
C「スイッチが押されたことを検知して意味を解釈しその指示を出力する」ブロック
の3つに分けられた。LCDは2行しかないので、読み出したディレクトリの最後に来たときは、(MORE)などの表示をし、そこで決定ボタンを押せば、次のディレクトリのグループが読み出され選択できるようにする。前のグループに戻るには、そのグループのトップにいる(UP)表示のところで決定ボタンを押し、前にもどる。
決定ボタンを押せば、表示された先頭ファイルの再生とみなしてDACへデータを送り始める。再生が終了すれば、前の位置のファイル名の表示をして次の入力を待つ。中断や中止は、再生中に決定ボタンを短く押すと「中断」、長く押すと「中止」とする。うむ、大体の動きはこれで良いようだ。こんどはこれをもう少し具体的にしていく作業に入ることにする。
汎用WAVデータの再生とUART版ソースの公開(2/2/09)
毎年続けている北海道スキー合宿に今年も行ってきた。空港からスキー場までのバス往復(2 時間はかかる)で、これまで考えていたLCD表示ロジックを色々考える。この種の思考にはこういう閉鎖空間で何も出来ないときが向いているようだ。
このあいだは、(MORE)の表示を作って、ここで決定ボタンを押せば次に行くようにしていたが、わざわざそれをするまでもなく表示がスムーズに出来る方法を思いついた。ダブルバッファーにすれば良いのだ。こうしておけばファイルの切れ目でディレクトリを頻繁に読み直す必要がなくなる。隣接した部分ではファイルアクセスをせず、沢山移動させたときに始めてディレクトリファイルを読み直す。
良いアイデアが浮かんで、それが可能なことが確認できたときの快感は、最近TVに良く出てくる「AHA」体験と言うのだそうだが、これはプログラミングの醍醐味のひとつだ。忘れないように揺れるバスの中で、メモにまとめた。
LCD操作機能の設計が進んできたが、その前にやることがある。WAV再生の汎用化である。それにUART版のソースコードでも、DAC再生の事例として公開すれば何かの役に立つかもしれない。多種のWAVデータが再生できるようにしてから公開することにする。
そもそもWAVファイルというのは、汎用的な音楽ファイルフォーマットの規格で、ヘッダーで多種多様の音楽ファイルが収容できる。リニアーPCMといっても種類を間違えると強烈なノイズになって機械は壊れないにしても精神衛生上良くない。少なくともサンプリングは44.1khz、22.05khz、データ長は16、8ビット、モードはステレオとモノ、これくらいは何もしなくても自動認識して再生できるようにしておきたい。
このロジックは簡単に出来た。BU9480Fは、モノーラルの時、Lチャンネルだけにデータを送れば出力が両方に出るということなので、モノーラルのときはRチャンネルを空振りするようにし、16ビットと8 ビットは処理を別にすれば、上記のWAVデータは全部再生できるはずだ(サンプリングの違いは最初のタイマーの設定で分けられる)。chaNさんのxatoiのように、関数のエントリーポイントを振り分ける手法をとらずに、デコードの度にブランチさせても時間的には余裕がありそうである。まあ、これはテストしてみればわかる。幸い、バッファーとSDカードアクセスの時間的余裕はかなりある。
スキーから帰った翌日、久しぶりに地下のオーディオルームで、CDからリッピングしたお気に入りのモーツアルトのクラリネット協奏曲をプレーヤーから再生しながら、上機嫌でプログラム開発をする。ロジックは大分前に考えてあったのでコーディングは簡単に済んだ。再生してみる。ははは、ほとんどの曲が超スロー再生になってしまっている。サンプリング周波数がおかしい。16ビットと8ビットの振り分け、モノとステレオはうまく行っているようだ。スロー再生は思い当たることがある。タイマーのプリスケールの指定をORでやっているので正しいプリスケールになっていない疑いが強い。
(1<<CS21)とか_BV(CS21)というAtmel社推奨のビットハンドリングはこういうとき意外に使いにくい。1にするときは簡単だが、0にするには反転してANDにしなければならない。混在するときは決め打ちするしかない。今度もそうした(誰か他に良い方法があれば教えてください)。ここの処理はデコード前なのでいくらでも増やせる。ついでにサンプリング周波数16khzのレコードも再生できるようにする。プログラムを修正し動かしてみた。
以前の22khz8ビットのファイルも正しく再生できるようになった。今まで音になっていなかった44khz16ビットモノーラルのゲームソフトの女性の声もちゃんと出る。単純に嬉しい。これでソースの公開の準備が整った。回路図も用意することにする。アナログの部分は単純なボルテージバッファーしかないので参考程度だが、強みはこれで今動いていることである。何かの手がかりになれば幸いである。
UARTのシリアルコンソールからSDカードのファイルリストを出して、再生する曲の指定ができるPCMプレーヤーのソースコードをAVRstudioのプロジェクトファイルの形でここに置きます。16/22.05/44.1khz、8/16ビット、モノ/ステレオのリニアPCMオーディオが再生できます。なお、UARTはTTLベースなので適当な変換(秋月のUSBアダプターなど)を通して接続してください。 boud rateは38400bps.8ビットノンパリティです。
修正:回路図に誤りがありました。レベルシフターが当初の図では74HC126になっていましたが、正しくは74VHC126です。(2/9/09)
| 固定リンク
「AVR」カテゴリの記事
- ソフトI2Cはクロックストレッチまで手を出してあえなく沈没(2017.09.02)
- オシロのテストどころかソフト開発で大はまり(2017.07.26)
- 超音波方式の人感センサーI2C化と新しいオシロ(2017.06.29)
- motionの動体検知はRaspi3の電源が安定しない(2017.04.16)
- 赤外線学習リモコンはデータ再現で挫折したまま進まず(2016.07.21)
コメント
私の場合、RAM容量削減と電源OFF時にEEPROMに保存したかったので曲番号をビットマップに割り当てて、どのビットをOFFするかをランダムにして再生するたびにそのビットをOFFするようにしました。
曲番号とはディレクトリリードしたときのファイル順です。
投稿: そら。 | 2009年2月 5日 (木) 19時39分
いつもコメントありがとうございます。
重複しないランダム再生で苦労されたということですが、
これは組み合わせ問題として、
1.配列のそれぞれに乱数を出して(配列より大きい乱数範囲)
2.乱数をソートして配列を組み替える
で出来ませんか。これ以上簡単と言われると、うーむ、今のところ思いつきませんね。
投稿: がた老 | 2009年2月 5日 (木) 12時16分
お疲れさまです。
だんだんと完成に近づいていますね。
ゆきさんのMP3プレーヤーを改造したときにランダム再生には苦労しました。
単なるランダムなら簡単なのですが、一度再生した曲をもう一度再生させないロジックに苦労しました。
私が思いもよらない何か簡単な方法があるのかなぁ。
投稿: そら。 | 2009年2月 3日 (火) 21時48分