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電信 と呼ばれている。是非、楽しんで頂きたい。

あっ…っ!あん!あんっあ!あんっあ!んあんっ!!あっ…っ!あん!んあんあ!んあん!あっ!んあ!んっあ!!あんっ!あっ!ん!あっ…っ!!あんあんあん!あんあんあん!あんあんあん!