2018年11月9日金曜日

【ALSA】PCオーディオ、フルビットsin波を出力し、それをキャプチャしてみた

最終的にはRapsberry Piでやりたいのですが、まずはLinuxで動かしてみたのが、
  ・PCのオーディオ出力端子にフルビットsin波を出力
  ・同信号をPCのオーディオLINE入力端子に接続し、キャプチャする
という動作です.

現在のLinuxのオーディオは、ALSAというドライバで実装されているらしい.いろんな事を出来るみたいだけどよくわかりません.
ともかく、今時のLinuxのディストリをinstallすればALSAが動くようになってるんじゃね?
「じゃね?」っていうのは、apt-get install alsa-dev みたいなことをやったのかどうか、もう忘れちゃったんだよね.なにせ、6月からこっち忙しくて自分の時間を持てなかったので、ALSA弄りで遊んでいるのは5ヶ月ぶりなんですよ.5ヶ月前に何をインストしたかなんて覚えてませんわ.

そんなわけで5ヶ月前までALSAの資料漁りをしとったわけですけど、結局のところALSAを解説する日本語書籍は無いっぽいです.なのでネットの諸情報をネチネチとこねくり回して「あ~動いたっぽいなぁ」と思ったので以下に記します.

とても参考になったサイトはこちらでした(日本語).ありがとうございます.
GitHubにも参考になるcodeがあったのでチラチラと見ました.

下記情報で貴方が損害を蒙ったとしてもわたしは知らないので、やるなら自己責任でやってくださいね.フルビット出力でスピーカ鳴らすとスピーカーや耳が故障するかもです.劇薬ですので.(わたしはオシロで波形観測だけしてます)

【環境】
Kona-Linux 4.0 pro
全てterminal windowでの操作.
ハードウエアは当ブログのこの記事で書いた中古Gateway
オンボードのIntel audioを使用   (audio cardは搭載せず)
PCオーディオ端子はこういう配線   (LINE入力をキャプチャする)
PCオーディオ出力(緑)→ボリウム→PCオーディオLINE入力(青) という信号の流れ.
ボリウムでレベルを下げないとキャプチャがサチるため.
サウンドデバイスファイルはこうなっていて、出力pcmC0D0p  キャプチャpcmC0D0c を使っている.(わたしの環境ではということで)
   ls /dev/snd
   by-path/   hwC0D2  pcmC0D0c  pcmC0D2c  seq
   controlC0  hwC0D3  pcmC0D0p  pcmC0D3p  timer
出力とキャプチャを同じデバイスで実行できるものなのか不明だったが、やってみたら動いた.

【いきなりソースコード】
2つあります.わたしのcodeはゲスなのを前もってお詫びしとく.動いたことを確認してからupしたのでたぶん動くと思います.大音響が出るからむやみにスピーカーを鳴らさないで.

1)sin.c
sin波をPCオーディオ出力端子に出すプログラム.(fs=48kHz)
エラー処理を割愛した病気codeだけど許して.
コンパイルはこれ→   gcc -lasound -lm sin.c -o sin
うごかすにはこんなかんじ↓
   sin      →Lch 1000Hz    Rch 333Hz    フルスケール
   sin 2000 1500 0.5        →Lch 2000Hz  Rch 1500Hz フルスケールの半分
止めない限り永久に出力しつづける.
オーディオデバイス指定は"default"にしてあるが、わたしの環境では"hw:0,0"と指定したのと同等である.hw:0,0はpcmC0D0p/pcmC0D0c のALSAにおける呼び名であり、上でリンクした日本語サイトの解説を読んだら理解できるかもよ.

2)adc.c
PCオーディオLINE入力端子をキャプチャするプログラム.(fs=48kHz)
エラー処理を割愛した病気codeだけど許して.
指定サンプル数でキャプチャを打ち切り、stdoutにLch,Rchの順でtab区切りで出力する.
コンパイルはこれ→   gcc -lasound adc.c -o adc
うごかすにはこんなかんじ↓
   adc                       →default動作、1024サンプルで打ち切り、hw:0,0
   adc 4096               →4096サンプルで打ち切り、hw:0,0
   adc 2048 hw:1,0    →2048サンプルで打ち切り、hw:1,0
リダイレクトでファイルに落とすとかは好きにしてね.ex.  adc > mycapfile
ファイル名をcapture.cにすりゃよかった気がする.

追記
3)周波数チャープ出力プログラムも作ってみた.   charp.c
4)M系列を出力するのも作ってみた.   Mseq.c


【フルビット出力】
このような結果を得ました.このMBDでは、フルビットかつMixer volume最大だと3.3Vppが出てきました.
なんで3.3Vppなのでしょうか? ありがちなのは、ADCのVrefに3.3Vを突っ込んでいるだけだろっていうやつかしら.

軽く調べたのだけど、PCのオーディオ出力レベルに厳密な規格は無いみたい.
この3.3Vppというのは1.167Vrmsです.コンスーマオーディオにありがちと云われる0dBV=1Vrmsとは異なるし、プロ用機器の0dBu=0.775Vrmsとも異なる.+4dBu=1.228Vrmsとも異なる.いずれとも似て非なるレベルです.
(0dBuは600Ωに1mWだってさ)

考えるだけ無駄だと思ったので放置プレイにしときます.

【alsamixerを使え】
出力が出ないとか、キャプチャがオールゼロだとか、そういうトラブルに見舞われたらミキサーを疑ってみたらいいかもしれません.

まず出力のミキサー調整は、alsamixer と打って出て来るこの画面で調整します.
(画面の様子が変だったら alsamixer -c 0 としたら良いかも)
PCオーディオ出力端子(緑)のレベルは、Master volumeとFront volumeで決まるようになっていました.他のMBDでも同じかどうかは知りません.

次にキャプチャのミキサー調整は、alsamixer -V capture と打って出るこの画面で調整します.
PCオーディオLINE入力端子に接続しているのだから、Input Source=Lineに設定する必要があります.これを怠るとシステムノイズがキャプチャされるばかりになってしまいます.
わたしの環境では、Capture volumeがキャプチャレベルの調節でした.他のMBDでも同じかどうかは知りません.
Capture volumeを最大にしてしまうと、フルビット入力レベルが10mVppとかいう極小電圧になってしまいます.アンプゲインが大きすぎるのです.
Capture volumeを24とか19まで下げて使うことにしました.ところが19の時ですら、150mVppでフルビットになってしまうのですからそれでもLINE入力と呼べるのかと疑問に思います.LINE入力なら2Vppでフルビットなどというオーダーが通常だと思いますから.
ちなみに、Capture volumeを5などに下げたら450mVppでフルビットなどと改善が期待されますがダメでした.なぜならMBDのLINE入力アンプが150mVppを超えるとサチってしまうのです.妙なレベル設定です.
マイク出力を拾うに適したレベル設定を志向しているのではないかと推測するのですが、考えるだけ無駄なので放置プレイにしときます.

【フルビットキャプチャ】
Capture volume=19
PCオーディオLINE入力=150mVpp
Lch=1000Hz     Rch=333Hz
キャプチャしたファイルを描画した波形.前半がLchで、後半がRchになっている.
振幅は、±30000を超えているので、ほぼ16bitフルビットです.

フィルタかけたりして遊べますね.遊んだらまたレポートします.

追記【サンプリング周波数の自由度】
Intel audioのサンプリング周波数設定の下限/上限はどうなっているのでしょうか?
APIの
    snd_pcm_hw_params_set_rate_near()
でサンプリング周波数をセットします.
いろいろなサンプリング周波数を試みた結果、4000~2999999Hzまでちゃんと動いているようです.上限がほぼ3MHzというのは驚きです.また、1Hz単位でセットできた風に見えるのですが、DDSの対応する周波数STEPがそんなに細やかであるというのも信じ難いです.なんだかなーと思いつつこれも放置プレイ.

ここで例えばサンプリング周波数を200kHzにしたら、PCオーディオ出力端子に100kHzを出せるようになるのでしょうか? やってみたけど、LPFのせいで約20kHzまでしか出ませんでした.

かしこ

0 件のコメント:

コメントを投稿