Linuxの音声再生環境を整える
ALSA (Advanced Linux Sound Architechture) は Linux用のサウンドAPI群です
1999年頃 前身である OSS(Open Sound System)が普及するまでは
サウンドボード毎にドライバも異なり再生環境を構築するのは特殊な作業でした
アプリケーションが OSSに対応し始めると一気に Linuxのサウンド環境が改善し
今まで「無音状態」だった Linuxシステムにマルチメディアという魅力が付与されたのです
Linux-2.6では ALSAがカーネルに取り込まれ標準機能となると
Windowsと同じように「何も意識しなくても再生環境は整っている」状況までなりました
ALSAが一気に普及できたのは OSSよりも高機能な上
OSS互換APIを持っていたため アプリケーションの移行がスムーズに進んだためです
ここでは 下記の検証環境で ALSAの環境構築までをレポートします
CPU | AMD Turion-MT37 2GHz |
---|---|
メモリ | DDR-400 1.5GB |
サウンド | SoundBlaster Live! Value |
OS | Linux-2.6.39 |
GCC | gcc-4.6.2 |
alsa-lib | alsa-lib-1.0.25 |
alsa-utils | alsa-utils-1.0.25 |
awesfx | awesfx-0.5.1d |
ALSAパッケージ構成とインストール
ALSA関連のパッケージは複数に別れています
ALSA公式ページ で配布されている各パッケージの役割を整理すると
alsa-firmware | 特定のサウンドボード向けファームウェア | |
alsa-driver | ドライバ本体 Linux-2.6以降は不要 | |
alsa-oss | liboss ALSA自体が既にOSSエミュレーションするので通常不要 | |
alsa-plugins | 追加プラグイン 通常不要 | |
alsa-lib | 基本ライブラリ libasound 必要 | |
alsa-utils | alsamixer や aplay などの基本アプリ | |
Linux-2.6以上であれば alsa-lib と alsa-utils のみで十分です
alsa-lib は下記のオプションでインストールしました
$ ./configure --prefix=/usr/local checking build system type... i686-pc-linux-gnu checking host system type... i686-pc-linux-gnu checking for a BSD-compatible install... /bin/install -c 〜 config.status: creating include/config.h config.status: executing depfiles commands Creating asoundlib.h... $ make 〜 $ su 〜 # make install 〜 #
aserverコマンドや libasoundライブラリがインストールされます
alsa-utils は下記オプションでインストールしました
$ ./configure --prefix=/usr/local --disable-xmlto --with-udev-rules-dir=/etc/udev/rules.d --with-asound-state-dir=/var/state checking for a BSD-compatible install... /bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p 〜 config.status: creating po/POTFILES config.status: creating po/Makefile config.status: executing depfiles commands $ make 〜 $ su 〜 # make install 〜 #
こちらは基本ツールがメインで bin/ 以下に下記のツールがインストールされます
aconnect alsamixer amidi aplay arecord aseqdump iecset alsaloop alsaucm amixer aplaymidi arecordmidi aseqnet speaker-test
音楽再生 MIDI再生 録音 設定ツール が一通り揃っています
speaker-test で音声が鳴るのを確認したら ALSA関連のインストールは完了です
後は mpg123など libasound対応のアプリを好きなだけインストールしましょう
$ speaker-test speaker-test 1.0.25 Playback device is default Stream parameters are 48000Hz, S16_LE, 1 channels Using 16 octaves of pink noise Rate set to 48000Hz (requested 48000Hz) Buffer size range from 128 to 32768 Period size range from 32 to 32768 Using max buffer size 32768 Periods = 4 was set period_size = 8192 was set buffer_size = 32768 0 - Front Left ^C $
もし SoundBlasterシリーズの音源カードを利用されているなら
MIDI再生の環境も整えてしまいましょう
ほとんどの SoundBlasterシリーズのカードは「サウンドフォント」をサポートしていて
ハードウェアでMIDIを鳴らすことができます
最近はゲーム等でも MIDIを鳴らす機会が減ってしまいましたが
SoundBlasterシリーズの魅力の一つとして このサウンドフォントサポートが挙げられます
ここでは サウンドフォントをシステムに読み込むための asfxloadをインストールして
実際にサンプルMIDIを演奏するところまでを紹介します
asfxloadは awesfxパッケージに含まれています
ソースコードを展開して configure 〜 make 〜 make install します
$ ./configure --prefix=/usr/local --with-sfpath=/usr/local/share/sounds/sf2 checking for a BSD-compatible install... /bin/install -c checking whether build environment is sane... yes checking for a thread-safe mkdir -p... /bin/mkdir -p 〜 config.status: creating etc/Makefile config.status: creating include/config.h config.status: executing depfiles commands $ make Making all in awelib 〜 gcc -g -O2 -o sfxtest sfxtest.o seq.o awelib/libawe.a /usr/local/lib/libasound.so -lrt -lm -ldl -lpthread -Wl,--rpath -Wl,/usr/local/lib -Wl,--rpath -Wl,/usr/local/lib make[1]: Leaving directory `/home/deer/admin/Alsa/awesfx-0.5.1d' $ su # make install 〜 #
configureではサウンドフォント配置先を /usr/local/share/sounds/sf2/ としました
インストールされるコマンドは 下記のとおりです
asfxload aweset gusload setfx sf2text sfxload sfxtest text2sf
サウンドフォントは SoundBlasterのドライバCDなどに含まれている
8mbgmsfx.sf2 を使いました ファイル名の通りGM準拠で8MBの容量があります
サウンドフォントディレクトリに 8mbgmsfx.sf2 をコピーして asfxloadでシステムにロードします
# ls /usr/local/share/sounds/sf2/ 8mbgmsfx.sf2 default-2m.bnk test.bnk xgmap.bnk README-bank emu8m.bnk xgdefault.bnk xgsfx.bnk ch12msup.bnk setfx-sample.cfg xgdrum.bnk # cat /proc/asound/Live/wavetableD1 Device: Emu10k1 Ports: 4 Addresses: 17:0 17:1 17:2 17:3 Use Counter: 0 Max Voices: 64 Allocated Voices: 0 Memory Size: 134217728 Memory Available: 134213632 Allocated Blocks: 1 SoundFonts: 0 Instruments: 0 Samples: 0 Locked Instruments: 0 Locked Samples: 0 # asfxload /usr/local/share/sounds/sf2/8mbgmsfx.sf2 # cat /proc/asound/Live/wavetableD1 Device: Emu10k1 Ports: 4 Addresses: 17:0 17:1 17:2 17:3 Use Counter: 0 Max Voices: 64 Allocated Voices: 0 Memory Size: 134217728 Memory Available: 126786844 Allocated Blocks: 527 SoundFonts: 1 Instruments: 1849 Samples: 526 Locked Instruments: 1849 Locked Samples: 526 #
SoundFontsの項がカウントアップされているのがわかります
(サウンドフォントはメモリの許す限り複数ロードできますが 検証環境では試してません)
また MIDI用のポートが 17:0 17:1 17:2 17:3 と 4つあることもわかります
ではサンプルとしてどこからか拾ってきた ワルキューレの伝説 を鳴らしましょう
$ aplaymidi -p 17:0 LEGENDofVALKYRIE.mid $
サウンドが鳴れば 無事にMIDI環境が動作しています
asfload のロードはシステム起動時に実行する必要があるため 起動スクリプト等に組込んで完成です
8bit 16bit 時代では高価な MIDI専用機を購入しなければ手に入らなかった
MIDI再生環境が 今やLinux上で再現できてしまいます 感慨深いものです
一方 ハードウェア音源の例では 上記 Roland SD-20 のようなものが挙げられます
最近の MIDI再生機器も小型化され USB接続可能となるなどの進化を遂げており
(通常 MIDI機器は専用のMIDIインターフェースで音源ボードと接続する)
実際筆者はこの SD-20を所持していて クリアな発声などそれなりの魅力もありますが
やはり ハードウェア音源はお金持ち向けという印象がぬぐえません
ちなみに Windows+DirectXは ソフトウェア音源上で MIDIを演奏する動作になってます
従って安物のオンボードサウンドチップでも 何も考えずにMIDIが鳴ります
(MIDI再生に必要なリソースは CPUが負担しているため
SoundBlasterご利用なら MIDI出力をサウンドフォント用ポートに切り替えたほうがよいでしょう)
トラブル事例
筆者の検証環境のみの特殊事例かもしれませんが 当初下記エラーが出て困っていました
$ aplay -L
Segmentation fault
$
$ aplay -L Segmentation fault $
で全く音声が鳴らないという事象です
原因を調査した結果 「-lライブラリ にて実行時リンクするライブラリに対して 動的リンクも行い長いシンボル名を dlopen() dlsym() dlclose() 繰り返すと不正終了する」
といった 日本語で表現するのも難しいほど 理解不能な現象でした
下記検証プログラム t_main.c で Segmentation fault が再現されました
#include#include int main () { int i; void *handle = NULL; void *target = NULL; for ( i = 0; i != 10; i++ ) { handle = dlopen ( "libz.so", RTLD_NOW ); if ( handle ) target = dlsym ( handle, "long___________long" ); else printf ( "failed dlopen()\n" ); dlclose ( handle ); printf ( "count=%d\n", i ); } return ( 0 ); }
/usr/local/lib/libz.so を実行時リンクする下記のバイナリを作って実行すると
$ gcc -lz -ldl -o t_main t_main.c $ ./t_main count=0 count=1 Segmentation fault $
カーネルの問題なのか glibcの問題なのか判りません 検証環境のみの現象かもしれません
alisa-lib が丁度この条件に引っかかったようでしたので
src/dlmisc.c の snd_dlopen() 関数部分を修正して対策しました
51 void *snd_dlopen(const char *name, int mode) 52 { 53 return dlopen(name, mode); 54 #ifndef PIC 55 if (name == NULL) 56 return &snd_dlsym_start; 57 #else 58 #ifdef HAVE_LIBDL 59 if (name == NULL) { 60 static const char * self = NULL; 61 if (self == NULL) { 62 Dl_info dlinfo; 63 if (dladdr(snd_dlopen, &dlinfo) > 0) 64 self = dlinfo.dli_fname; 65 } 66 name = self; 67 } 68 #endif 69 #endif 70 #ifdef HAVE_LIBDL 71 return dlopen(name, mode); 72 #else 73 return NULL; 74 #endif 75 }
53行目にあるように いきなり return dlopen(name, mode); で返るように修正しました
name= にあたる部分の /usr/local/lib/libasound.so.2 が長い名前だったことが
今回の不具合に該当してしまったようです
$ aplay -L null Discard all samples (playback) or generate zero samples (capture) default:CARD=Live SB Live! Value [CT4670], ADC Capture/Standard PCM Playback Default Audio Device sysdefault:CARD=Live SB Live! Value [CT4670], ADC Capture/Standard PCM Playback Default Audio Device front:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback Front speakers rear:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback Rear speakers center_lfe:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback Center and Subwoofer speakers surround40:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback 4.0 Surround output to Front and Rear speakers surround41:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback 4.1 Surround output to Front, Rear and Subwoofer speakers surround50:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback 5.0 Surround output to Front, Center and Rear speakers surround51:CARD=Live,DEV=0 SB Live! Value [CT4670], ADC Capture/Standard PCM Playback 5.1 Surround output to Front, Center, Rear and Subwoofer speakers iec958:CARD=Live,DEV=0 SB Live! Value [CT4670], Multichannel Capture/PT Playback IEC958 (S/PDIF) Digital Audio Output $
aplay -L も正しく結果を返すようになり 音楽も鳴りました