OpenSolarisで、音ス
テンキ セイロウ ナレド カゼ ツヨシ
あれ? ナミ タカシ じゃ、無かったっけ? いえいえ、この地から打電するなら この電文しかありません。
ことほど左様に、この地は風が強いんであります。もし風力発電機を設置したら、1年分 の電気が1,2月で賄えるほどだと思います。これって、ECOには最適かと思いますが、人様には 最低ですね。
昔、体育の授業かなにかで習ったと思うんだけど、0.6m/秒 だかの風で体感温度が1度 下がるとか。そうすると、この地は、お天気先生の森田さんが言う気温よりは、大体10度は低いと 思わないといけないね。車の中だと、お天道様が出てれば熱いくらいなのに!
でも、風に向かって走れ、で、チャリを駆って出かけるのでありました。が、今日はどうした事か 急にお腹の調子が悪くなり、近くにあったコンビニのトイレに駆け込んだのであります。 (次回から外出時は、バカボンパパの腹巻で、完全武装しよう。)
ほっとして壁に目をやると何やら見慣れないものが、、、音姫ボタンなるものが ついていたんです。押したら、どんな音するんだろう? ちょっと興味を引きましたが 、私は、ハルナ.アイではないので、躊躇ってしまいましたよ。
VMWAREとミスマッチ
という事情から、Solarisで音したいなと、思っってしまいました。 これなら、誰はばかる事なく、自由に音出しできますからね。 (本当なら、Solarisの本性を見極めるべく、ZONEとやらの積もりだったんですが。。。)
で、どうせまたデバイスを直接に叩くんだなと思って、それらしいデバイスが無いか、 /devを覗いてみたんだ。
でも、それらしいものは見つからず。ちと不安になって、ネットを検索してみたら Solarisで音を出す と言うずばりの ページが見つかった。どうも、/dev/audio が必須のようだ。この方はBlade100を 使ってるようで、私のはただのVMWAREだから(そして、OpenSolarisだから)、差を 付けられているのかなあ?
一応、man audio してみると、ちゃんと説明が出てくる所をみると、OpenSolarisと 言えども、ちゃんとaudioをサポートしてるっぽい。すると、VMWAREが手抜きしたか 出荷を忘れているかだな。
再びネットをさ迷ってみたら、 OpenSolaris 2009.06 on VMplayer 3.0 for linux audio 境遇が同じ人に巡り合った。ポインターがあったので参照してみると、 Jurgen Keil's Audio Drivers for Solaris 俺のドライバーも良かったら使ってみてちょ。親切なドイツ人だ事。
早速、頂いてきた。pkg installでいいんかいと思って試してみたら拒否されたよ。 ふと昔のSolaris時代を思い出して
sakae@solaris:~$ pfexec pkgadd -d ./audio-1.8-i86pc.pkg The following packages are available: 1 TOOLSahlp Audio Driver Framework (i86pc) 1.8 2 TOOLSbpci Soundblaster 16/128 PCI (ES1370/1371) Driver (i86pc) 1.8 3 TOOLSemu Soundblaster Audigy PCI (EMU10Kx) Driver (i86pc) 1.8 4 TOOLSi810 Audio Driver for Intel ICH audio controller (i86pc) 1.8 5 TOOLSva686 Audio Driver for VIA VT82C686A AC97 audio controller (beta) (i86pc) 1.8 6 TOOLSva8233 Audio Driver for VIA VT8233 AC97 audio controller (i86pc) 1.8 Select package(s) you wish to process (or 'all' to process all packages). (default: all) [?,??,q]:
入れてみたら、最後にリブートしてちょって言われて、rebootはこうやるんだよと 説明文まで載せてくれていた。親切な人だ事。
shutdown -y -i6 -g0
6を止めて0にすると、マシンが止まるけどね。ひょっとしたら、SMFがらみで、新しい rebootの方法が有ったりして、、、どうなんしょ?
rebootして、認識したか見てみる。
sakae@solaris:~$ dmesg|grep audio Jan 28 15:29:42 solaris pci_pci: [ID 370704 kern.info] PCI-device: pci1274,1371@1, audio13710 Jan 28 15:29:42 solaris genunix: [ID 936769 kern.info] audio13710 is /pci@0,0/pci15ad,790@11/pci1274,1371@1 Jan 28 15:29:42 solaris audio1371: [ID 328162 kern.info] PCI-device: pci1274,1371, audio13710, CT5880C (rev. 0x02) at irq 5 Jan 28 15:29:42 solaris audio1371: [ID 216691 kern.info] AC97: primary codec, rev. 2.1 or earlier, vendor id1:0x4352,id2:0x5913, 16-bit DAC, 16-bit ADC, 3D-stereo mode 0, aux LNLVL_OUT Jan 28 15:29:42 solaris audio1371: [ID 885429 kern.info] AC97: extid 0x0000, powerdown status 0x000f sakae@solaris:~$ grep audio /etc/path_to_inst "/pci@0,0/pci15ad,790@11/pci1274,1371@1" 0 "audio1371"
sakae@solaris:~$ ls -l /dev/audio lrwxrwxrwx 1 root root 7 2010-01-28 15:29 /dev/audio -> sound/0 sakae@solaris:~$ ls -l /dev/sound/0 lrwxrwxrwx 1 root root 63 2010-01-28 15:29 /dev/sound/0 -> ../../devices/pci@0,0/pci15ad,790@11/pci1274,1371@1:sound,audio
おいら的には、dir名に英数字以外を使っちゃうSunの人の神経を疑いたいぞ。 まあ、Busを素直に表現しようとすると、こうせざるを得ないっても理解は出来るんですが。。 ついでなので、パーミションを緩くしておきました。
音出るかな?
manによると、お試し音が用意されてるようだ。どんな音があるか、見て(聞いて)みるかな。 えっと、場所は
sakae@solaris:/usr/share/audio/samples/au$ ls -l total 863 -r--r--r-- 1 root bin 2407 2009-05-15 00:51 bark.au -r--r--r-- 1 root bin 12494 2009-05-15 00:51 bong.au -r--r--r-- 1 root bin 31251 2009-05-15 00:51 bubbles.au : -r--r--r-- 1 root bin 989 2009-05-15 00:51 touchtone.9.au -r--r--r-- 1 root bin 967 2009-05-15 00:51 touchtone.pound.au -r--r--r-- 1 root bin 1027 2009-05-15 00:51 touchtone.star.au -r--r--r-- 1 root bin 12920 2009-05-15 00:51 train.au -r--r--r-- 1 root bin 12622 2009-05-15 00:51 whistle.au
いろいろな音源があるなあ。ファイル名からは想像が付かないようなものもある。 これはもう、聞いてみる鹿。ええい、この際だから、全部聞いちゃえ!
sakae@solaris:/usr/share/audio/samples/au$ for f in *.au > do > echo $f > cat $f > /dev/audio > done bark.au bong.au :
あれ、音しないよ。何でだ? エラーにもなっていないし、やり方が悪いのか? 再び、manをさ迷うと、mixerctlなんてのに出くわした。そうか、mixerで音を絞って いるかも知れないな。そなら実行してむる。
sakae@solaris:/usr/share/audio/samples/au$ mixerctl デバイス /dev/audioctl: 名前 = SUNW,CS4231 バージョン = 02,CT5880C 構成 = SB16PCI /dev/audioctl はオーディオミキサー機能をサポートしていません
ありゃ、安物はだめだってか? そう言われたって、ハードは制約があって交換出来ないしなあ。 まてよ、ボード自身にボリュームが付いているんではなかろうか。そしてそのボリュームが 絞られているって事じゃないでしょうかねぇ。(と、水谷豊演じる、あの刑事さん風にに考えてみたんだ。)
冒頭で紹介されてた、中を覗き込むプログラムを動かしてみると、
--- record --- sample_rate = 8000 channels = 1 precision = 8 encoding = 1 : AUDIO_ENCODING_ULAW gain = 127 port = 1 buffer_size = 24576 --- play --- sample_rate = 8000 channels = 1 precision = 8 encoding = 1 : AUDIO_ENCODING_ULAW gain = 127 port = 1 buffer_size = 24576 monitor_gain = 0 output_muted = 0
ボリュームって、gainの事かいなと思って、ゲインを上げてみたよ。サンプルプログラム よ、ありがとう。(コンパイルエラーが出るのは、お約束って事で、エラー潰ししましたけど)
再び、音を聞いてみると、にわとりの鳴き声やら、ドアのチャイムの音やら、トイレの 水を流す音やら(ひょっとして、これが音姫なるものなんでしょうかね)、汽車の音やら いろいろ詰まっていたよ。ドラ娘御用達のゴングの音まであった。
とまあ、試運転はこれでいいしょ。
audio プログラミング
中覗きプログラムがエラッたと書いた手前、修正内容を載せておくのが、礼儀だな。
#include <sys/audio.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> // audio_prinfo構造体の中身を表示する void foo( const struct audio_prinfo *p ) { printf( "sample_rate = %d\n", p->sample_rate ); printf( "channels = %d\n", p->channels ); printf( "precision = %d\n", p->precision ); printf( "encoding = %d : ", p->encoding ); switch ( p->encoding ) { case AUDIO_ENCODING_ULAW: printf( "AUDIO_ENCODING_ULAW" ); break; case AUDIO_ENCODING_ALAW: printf( "AUDIO_ENCODING_ALAW" ); break; case AUDIO_ENCODING_LINEAR: printf( "AUDIO_ENCODING_LINEAR" ); break; } printf( "\n" ); printf( "gain = %d\n", p->gain ); printf( "port = %d\n", p->port ); printf( "buffer_size = %d\n", p->buffer_size ); // 後は省略 } // デバイスの状態を読み込み表示する struct audio_info read_info( int fd ) { struct audio_info info; // 情報を取得する if ( ioctl( fd, AUDIO_GETINFO, &info ) < 0 ) { // 失敗 fprintf( stderr, "It failed to get audio info\n" ); return info; } printf( "Succseed to get info\n" ); printf( "--- record ---\n" ); foo( &info.record ); printf( "--- play ---\n" ); foo( &info.play ); printf( "\n" ); printf( "monitor_gain = %d\n", info.monitor_gain ); printf( "output_muted = %d\n", info.output_muted ); return info; } int main( int argc, char *argv[] ) { int fd; // 開く fd = open( "/dev/audio", O_RDWR ); if ( fd < 0 ) { // 失敗した fprintf( stderr, "It failed to open /dev/audio\n" ); return 0; } // デバイスの情報を表示する read_info( fd ); // 閉じる close( fd ); return 0; }
何の事はない。冒頭に1行追加しただけである。そして、ボリュームを回したと書いたが 、回し過ぎて壊してしまうのも癪なので、取り扱い説明書を見たよ。ボリュームは、0から 255の範囲ですって。初期値が中点になってたんだな。それで聞こえなかったと言う事は、 おいらの耳が劣化してるんだな。悲しいけど、現実だ。
取り扱い説明書を見ていると、encodingの事が熱く書かれている。ulawがデフォって、 どう思っても尋常じゃないな。音質の悪い電話回線用のフォーマットだもの。 でも、unixの成り立ちに思いを馳せると、頷けるように なる。
だって、unixの生誕の地はAT and Tを親会社に持つのベル研。(ベルって、電話を 発明した、グラハム・ベルさんの事だよね。それから、 ATTって、アメリカの電信・電話会社ね。日本だと、NTT)親会社の機嫌をそこねないように気遣いした。 Sunは、最初BSD系だったけど、Solaris2 にする時、寝返ってATT系unixにしちゃったから 、デフォが電話フォーマット。(サンプル音にも電話のタッチトーンが全キー分入っていると 言う、念のいれ様)ああ、歴史物語になっちゃっちゃなあ。
電話が出てきたんなら、電信もやっとくれ、探してみたけど、それらしいのは無かった。 ならば記念に、モールス信号発生器でも作っておくか。(これ、去年やりましたよ。でも 生憎、OpenSolarisにOSSはまだ導入されていないので、Solaris風味でやります。)
// mosc (Morse tone generator) for OpenSolaris // Usage: echo morse-data | ./mosc // Data mean 0:end, 1:dot, 2:char sep, 3:dash, 4:word sep // dot-speed(in MS) can change by env-name "dotSPEED" #define SIZE 16 // point number for 500Hz @ 8000Hz samplings #define SPDNAME "dotSPEED" // env-name for dot-speed #define DEFSPEED 80 // default dot-speed in [ms] #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/types.h> #include <sys/uio.h> #include <unistd.h> #include <sys/audio.h> #include <sys/stat.h> int fd,dot; short int mrk[SIZE] = { 0,11987,22229,29233,31980,30070,23780,14027, 2232,-9888,-20569,-28254,-31824,-30760,-25216,-16000 }; short int sps[SIZE] = { 0 }; void tone(short *buf, int n){ int cnt; cnt = dot * n; while( cnt-- ){ write(fd, buf, sizeof(short) * SIZE); } } int setup_audio(){ int fd; struct audio_info info; fd = open( "/dev/audio", O_RDWR ); if ( fd < 0 ) { fprintf( stderr, "Failed to open audio device\n" ); exit(1); } if ( ioctl( fd, AUDIO_GETINFO, &info ) < 0 ) { fprintf( stderr, "Failed to get audio info\n" ); exit(2); } info.play.sample_rate = 8000; info.play.channels = 1; info.play.precision = 16; info.play.encoding = AUDIO_ENCODING_LINEAR; info.play.gain = 250; info.play.port = AUDIO_HEADPHONE; if ( ioctl( fd, AUDIO_SETINFO, &info ) < 0 ) { fprintf( stderr, "Failed to set audio info\n" ); exit(3); } return fd; } main(int argc, char *argv[]){ int c; dot = getenv(SPDNAME) ? atoi(getenv(SPDNAME)) : DEFSPEED; dot = dot >> 1; fd = setup_audio(); while(c = (getchar() - '0') ){ if (c == 1 || c == 3){ tone(mrk, c); tone(sps, 1); } else { tone(sps, c); } } close(fd); exit(0); }
audioデバイスを使えるようにする部分は、サンプルから有り難く頂いてきた。デバイス をオープン出来てしまえば、普通にファイル操作する感覚で使える所が嬉しい。
今回は、綺麗な音で聞きたかったので、正弦波テーブル(と無音テーブル)を用意した。 耳にやさしい音程という事で、500Hzでいく。そうすると、一つの正弦波は、周期が2msと なる。これを幾つ並べるかで、短点の周期を決めている。
sakae@solaris:~/work$ echo 3131233134313123313431121413332132333330 | ./mosc sakae@solaris:~/work$ export dotSPEED=100 sakae@solaris:~/work$ echo 3131233134313123313431121413332132333330 | ./mosc
モールスデータは、1が短点3が長点とした。2は文字区切りで、4は単語区切り。0は、 アプリケーション終了だ。このらのストリームを、標準入力から流し込む。短点スピード は、環境から取ってくる事にした。なお、このアプリは裸で使う事を意図してないので 入力データの検査はやっていない。(いいのか。そんな事で)
音を聞いてみると、途中で時々雑音が混じる。何故だろう? 同じ事を、他のマシンで やってみるかな。
7V電信符号
とまあ、今はプロの世界からもすっかり姿を消してしまった電信であるが、今使って いるのは、アマチュア無線ぐらい。アマチュア無線も高齢化が進み、電信を扱う人種は RedBookに載るぐらいの絶滅種になってしまった。
これではいかん、モールスの楽しさを後世に残さねばと立ち上がった人が居る。 その人の努力によって、楽しいモールス符号が発明された。 7V電信 と呼ばれている。是非、楽しんで頂きたい。
あっ…っ!あん!あんっあ!あんっあ!んあんっ!!あっ…っ!あん!んあんあ!んあん!あっ!んあ!んっあ!!あんっ!あっ!ん!あっ…っ!!あんあんあん!あんあんあん!あんあんあん!