6. 音声信号処理ソフト ALSAとPortAudio

 Linuxで音声処理をするための基盤となるALSAと、リアルタイムサウンド処理用のオープンソースC言語ライブラリーPortAudioについて概説し、インストールと使用方法を説明します。なお、インストールはPCからSSHターミナルエミュレータ(Poderosaなど)を経由して行います。



1.ALSAの概要

 ALSA(Advanced Linux Sound Architecture)は、Linuxにおいて高機能なサウンドシステムを提供するためのソフトウェア群です。
 ALSAは多種類のサウンドカードに対応するデバイスドライバーと、シンプルでポータビリティーに優れたAPI(Application Program Interface)を提供します。加えて、それ以前はステレオ音声が限界だった処理から、多チャンネルのサラウンド音声にも対応できるようになっています。
 APIにはカーネルAPIとライブラリーAPIの2種類があります。アプリケーションプログラマ-には、カーネルAPIではなく、ライブラリーAPIを使用するよう推奨されています。ライブラリーAPIはカーネルAPIの機能を100%カバーすると同時に、使いやすさが大幅に改善されているためです。また将来の修正や互換コードはライブラリAPIに配置される可能性があるとしています。
 これらのライブラリーについては、ALSA project - the C library referenceに詳細情報があるので参照してください。しかし、今回のプロジェクトでは、後に述べるPortAudioライブラリーを使用するので、ALSAのAPIを直接操作することはないと思います。


2.ALSAのインストール

 ALSAドライバーはLinuxのカーネルに含まれているので、インストールは不要です。ただし、PortAudioの構成スクリプトを使う場合にALSA SDKを探すようなので、次のインストールをしておきましょう。

$ sudo apt-get update
$ sudo apt-get install libasound-dev


 これで、プログラム作成時に便利なAPI群libasound2-devがインストールされます。ALSAのバージョンは、次のようにして確認することができます。

$ cat /proc/asound/version
Advanced Linux Sound Architecture Driver Version k4.19.97+.

3.ALSAの使い方

 ALSAは、今後の音声信号処理環境の設定やテストなどで頻繁に用いることになります。現時点では、音声信号プロセッサーであるRaspberry Pi Zeroにマイクもイヤフォンも接続できてないので、ALSAのすべての機能を試すことはできません。
 ここでは代表的なコマンドを紹介するにとどめます。
①サウンド再生

 ALSAによるサウンド再生にはaplayコマンドを使用します。多くのオプションがあるのでヘルプで表示させた一部を例示します。
$ aplay --help Usage: aplay [OPTION]... [FILE]... -h, --help help --version print current version -l, --list-devices list all soundcards and digital audio devices -L, --list-pcms list device names -D, --device=NAME select PCM by name : (省略) :

 次は、すべてのサウンドカードとオーディオデバイスを表示したものです。
$ aplay -l **** ハードウェアデバイス PLAYBACK のリスト **** カード 0: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA] サブデバイス: 7/7 サブデバイス #0: subdevice #0 サブデバイス #1: subdevice #1 サブデバイス #2: subdevice #2 サブデバイス #3: subdevice #3 サブデバイス #4: subdevice #4 サブデバイス #5: subdevice #5 サブデバイス #6: subdevice #6 カード 0: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 IEC958/HDMI [bcm2835 IEC958/HDMI] サブデバイス: 1/1 サブデバイス #0: subdevice #0 カード 0: ALSA [bcm2835 ALSA], デバイス 2: bcm2835 IEC958/HDMI1 [bcm2835 IEC958/HDMI1] サブデバイス: 1/1 サブデバイス #0: subdevice #0


②サウンドの録音

 ALSAによるサウンドの録音にはarecordコマンドを使用します。これもヘルプで表示させた一部を例示します。
$ arecord --help Usage: arecord [OPTION]... [FILE]... -h, --help help --version print current version -l, --list-devices list all soundcards and digital audio devices -L, --list-pcms list device names -D, --device=NAME select PCM by name : (省略) :


③スピーカーのテスト

 ずばりspeaker-testコマンドでテストできますが、これもオプションが多いのでヘルプで確認します。
$ speaker-test --help speaker-test 1.1.8 Usage: speaker-test [OPTION]... -h,--help help -D,--device playback device -r,--rate stream rate in Hz -c,--channels count of channels in stream -f,--frequency sine wave frequency in Hz -F,--format sample format -b,--buffer ring buffer size in us -p,--period period size in us -P,--nperiods number of periods -t,--test pink=use pink noise, sine=use sine wave, wav=WAV file -l,--nloops specify number of loops to test, 0 = infinite -s,--speaker single speaker test. Values 1=Left, 2=right, etc -w,--wavfile Use the given WAV file as a test sound -W,--wavdir Specify the directory containing WAV files -m,--chmap Specify the channel map to override -X,--force-frequency force frequencies outside the 30-8000hz range -S,--scale Scale of generated test tones in percent (default=80) 認識されるサンプルフォーマット: S8 S16_LE S16_BE FLOAT_LE S24_3LE S24_3BE S32_LE S32_BE

 チャンネルを2つにして試しています。
$ speaker-test -c2 speaker-test 1.1.8 再生デバイス: default ストリームパラメータ: 48000Hz, S16_LE, 2 チャネル 16 オクターブのピンクノイズを使用 レート 48000Hz (要求値 48000Hz) バッファサイズ範囲 480 〜 32768 ピリオドサイズ範囲 480 〜 32768 最大バッファサイズ 32768 を使用 ピリオド数 = 4 period_size = 8192 で設定 buffer_size = 32768 で設定 0 - Front Left 1 - Front Right ピリオド時間 = 5.143655 0 - Front Left 1 - Front Right ピリオド時間 = 5.79840 : :


④音量を変更する

 マイク入力やスピーカー出力などの音量はalsamixerコマンドで変更することができます。poderosaで操作すると画面が乱れるので、WindowsリモートデスクトップでRaspberry Pi Zeroに接続してLXTerminalを起動します。LXTerminalで「alsamixer」と入力すると下図のようなミキサー画面が表示されます。
 矢印キーと画面表示の機能キーを使ってビジュアルに変更でき、[ESC]キーで終了すると設定値が反映されます。

4.PortAudioの概要

 PortAudioは、リアルタイムオーディオ入出力用のオープンソースC言語ライブラリーです。ハードウェアのオーディオインターフェイスから、リアルタイムオーディオストリームを取得および出力できる関数を提供しています。ネイティブオーディオAPIを直接処理する複雑さを隠して、オーディオソフトウェアの開発が簡素化できるように設計されています。
 PortAudioは、録音、編集、ミキシングアプリケーション、ソフトウェアシンセサイザー、エフェクトプロセッサ、音楽プレーヤー、インターネットテレフォニーアプリケーション、ソフトウェア無線などを実装するために使用されています。
 サポートするプラットフォームは、MS Windows、Mac OS X、およびLinuxが含まれ、サードパーティの言語バインディングにより、Java、C ++、C#などの他のプログラミング言語からPortAudioを呼び出すことができます。


5.PortAudioのAPI

 PortAudioは、すべてのプラットフォームに統一されたAPIを提供しています。
 PortAudio処理モデルは、ホストAPI、オーディオデバイス、およびオーディオストリームの3つの抽象化によって構成されています。
①ホストAPI

 プラットフォーム固有のネイティブオーディオAPIです。Linuxの場合ではALSAなどのHost APIと直接対話することなく、PortAudioを簡単に使用できます。

②オーディオデバイス

 オーディオデバイスには、名前、サポートされているサンプルレート、サポートされている入力および出力のチャネル数などの固有の機能があります。PortAudioは、利用可能なデバイスを列挙し、デバイスのこれらの機能を照会することができます。

③オーディオストリーム

 デバイスからのアクティブなオーディオ入出力を管理します。ストリームには、半二重(入力または出力)または全二重(同時入力および出力)があります。ストリームは、特定のサンプル形式、バッファサイズ、および内部バッファリングレイテンシで特定のサンプルレートで動作します。これらのパラメーターは、ストリームを開くときに指定します。オーディオデータは、ユーザーが提供する非同期コールバック関数を介して、または同期読み取り/書き込み関数を呼び出すことにより、ストリームとアプリケーションの間で通信されます。

 PortAudioは、ネイティブオーディオAPIでサポートされている形式に関係なく、8、16、24、および32ビット整数形式と32ビット浮動小数点のさまざまなサンプル形式でオーディオ入出力をサポートしています。PortAudioは、インターリーブ形式と非インターリーブ形式(チャネルごとに個別のバッファ)の両方のマルチチャネルバッファもサポートし、必要に応じて自動的に変換を実行します。

 PortAudio APIが提供する機能は以下の通りです。
  ・ライブラリの初期化と終了
  ・利用可能なホストAPIを列挙する
  ・グローバルに、または各ホストAPI内で利用可能なデバイスを列挙する
  ・デフォルトまたは推奨のデバイスとデバイス設定を見つける
  ・サポートされているオーディオデータ形式やサンプルレートなどのデバイス機能を見つける
  ・オーディオストリームを作成して、デバイス間でオーディオを取得したり出力したりする
  ・ストリームのタイミング情報を提供して、アプリケーションの他の部分とオーディオの同期をサポート
  ・バージョンおよびエラー情報を取得する


6.PortAudioのインストール

 次の手順でインストールと設定を進めます。
①PortAudioをダウンロードして解凍(2016年10月30日版)

$ cd $ wget http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz $ tar zxvf pa_stable_v190600_20161030.tgz


②PortAudioのコンパイルとインストール

$ cd $ cd portaudio $ ./configure && make $ sudo make install
 "/usr/local/lib" にPortAudioの関連ファイルが出来ていれば成功です。


③環境変数の登録

 "~/.bashrc" に下記のexport文を追加することによってライブラリの環境変数を設定します(末尾に追加)。続いて再起動します。
$ cd $ sudo nano .bashrc export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib $ sudo reboot


④動作確認

 PortAudioのexampleフォルダーにはいくつものサンプルプログラムが収納されています。まだ音出しができる状態ではないので、デバイス情報など使用可能なデバイスを一覧表示するプログラム、pa_devs.cをコンパイルして実行してみましょう。
$ cd $ cd portaudio/examples $ gcc pa_devs.c -lportaudio $ ./a.out
 以下の内容が表示されます。
Expression 'alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 923 Expression 'alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 923 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround21 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround40 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround41 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround50 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround51 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.surround71 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.iec958 ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device' ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory ALSA lib conf.c:5036:(snd_config_expand) Args evaluate error: No such file or directory ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM bluealsa ALSA lib confmisc.c:1281:(snd_func_refer) Unable to find definition 'defaults.bluealsa.device' ALSA lib conf.c:4568:(_snd_config_evaluate) function snd_func_refer returned error: No such file or directory ALSA lib conf.c:5036:(snd_config_expand) Args evaluate error: No such file or directory ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM bluealsa Expression 'alsa_snd_pcm_hw_params_set_period_size_near( pcm, hwParams, &alsaPeriodFrames, &dir )' failed in 'src/hostapi/alsa/pa_linux_alsa.c', line: 923 PortAudio version: 0x00130600 Version text: 'PortAudio V19.6.0-devel, revision 396fe4b6699ae929d3a685b3ef8a7e97396139a4' Number of devices = 3 --------------------------------------- device #0 [ Default Output ] Name = bcm2835 ALSA: IEC958/HDMI (hw:0,1) Host API = ALSA Max inputs = 0, Max outputs = 8 Default low input latency = -1.0000 Default low output latency = 0.0016 Default high input latency = -1.0000 Default high output latency = 0.0348 Default sample rate = 44100.00 Supported standard sample rates for half-duplex 16 bit 8 channel output = 44100.00, 48000.00, 88200.00, 96000.00, 192000.00 --------------------------------------- device #1 Name = bcm2835 ALSA: IEC958/HDMI1 (hw:0,2) Host API = ALSA Max inputs = 0, Max outputs = 8 Default low input latency = -1.0000 Default low output latency = 0.0016 Default high input latency = -1.0000 Default high output latency = 0.0348 Default sample rate = 44100.00 Supported standard sample rates for half-duplex 16 bit 8 channel output = 44100.00, 48000.00, 88200.00, 96000.00, 192000.00 --------------------------------------- device #2 Name = dmix Host API = ALSA Max inputs = 0, Max outputs = 2 Default low input latency = -1.0000 Default low output latency = 0.0213 Default high input latency = -1.0000 Default high output latency = 0.0213 Default sample rate = 48000.00 Supported standard sample rates for half-duplex 16 bit 2 channel output = 48000.00 ----------------------------------------------


7.PortAudioによるプログラミング

 先に述べた、PortAudioのexampleフォルダーのサンプルプログラムを読むことは、PortAudio独特のプログラム構造を理解する上で大変参考になります。PortAudioのサイトには膨大な量のドキュメントがあり、APIやデータ構造についての詳細な情報を得ることができます。とりわけ、PortAudio Tutorialsはぜひ一読をお勧めします。
 以下に、その骨格になっている「PortAudioを使用したプログラミング」を紹介しておきます。

 これは、コールバック手法を使用してPortAudioアプリケーションを作成する手順です。
 ・オーディオ処理が必要なときにPortAudioによって呼び出されるコールバック関数を記述します。
 ・PAライブラリを初期化し、オーディオI / Oのストリームを開きます。
 ・ストリームを開始します。これで、コールバック関数がバックグラウンドでPortAudioによって
  繰り返し呼び出されます。
 ・コールバックでは、inputBufferからオーディオデータを読み取ったり、outputBufferにデータを
  書き込んだりできます。
 ・コールバックから1を返すか、stop関数を呼び出して、ストリームを停止します。
 ・ストリームを閉じて、ライブラリを終了します。


 今回はALSAとPortAudioという、プロジェクト必須の音声信号処理ソフトのインストールを行いました。どちらもその機能は多岐にわたり複雑です。折に触れ、関連ドキュメントを参照することが必要です。
 さて次回は、音声信号プロセッサーRaspberry Pi ZeroにUSBミニマイクを接続してテストすると共に、ここまでのインストールで形成された音声信号処理環境を確認します。盛りだくさんの内容になると思います。お楽しみに!