音のMagic

先月号のCQ誌に、電信用のAFフィルターの製作記事が出ていた。ノイズや混信した信号から 、聞きたい(電信)信号だけをより分けようというハードウェアだ。

面白いのは、共振回路がLとCで構成されている点だ。トラ戯等には必ず載っている、RとC を組み合わせた回路じゃない事。当然部品にはばらつきがあって、計算通りにいかないので 補正が必要だし、時と場合によっては、共振周波数を自由に変えられるようにしたい。

そうなると、RCの回路の場合Rを変えざるを得なくなり、回路が複雑になってしまう。 そこで、LC回路を使って、Lを可変にしちゃおうという作戦。大きな容量のLを可変に するって、とても難儀な事だけど、非常にうまく解決してる。さすがOM(長老)さんだ わいと、感心しました。

この記事の中で、調整はどうするって説明があり、面白いURLが紹介されてました。 コンピュータを用いた音の実験 中にある、発信器を使いましょう。こういうの、いいですねぇ。

発信器だけではなく他のソフトも非常に充実してた。手作りの教材で、面白さを教えてくれる先生って素敵。そして、それぞれのソフトに ユーモアある名前を付けちゃう感性に敬服します。

上記は、高校生向けだけど、大学生向けには、 ディジタル信号処理 (基礎編) が、お勧め。

以上は音に関する工学的に事項だけど、人間の聴覚と言う面でみると 音響心理学 を基点に、聴覚の話が有ったり、 等ラウドネス曲線 とか ヴェーバー‐フェヒナーの法則 まで出てきたりして、興味は尽きない。

音の高速再生とスロー再生

を、pdで出来ますか? こういう事は考えた事も無かったので即答出来なかった。でも、充実 した部品が揃っているpdだから、きっと出来るだろう。ヒントを求めて pddoc の9章あたりを見ていた。そしたら、再生のバリエーション の所で答えが見つかった。

配列のINDEXのアクセス間隔を可変にちゃうとは、アイデアだなあ。鋸歯状波発生器で、0から だんだん1に近づいていく波形を作り、それに、配列サイズを乗算してINDEXを求めている。 発信器の周期を変えれば、配列の読み出しスピードを変化させられるって訳だ。 このパッチは他にも、音ファイルの指定方法や配列への取り込み方法の例になっているので 参考になるなあ。

早速、このパッチをFreeBSDで実行しようとすると、下記のようなつれないエラーが 出てきたよ。

tried /usr/home/sakae/patch/expr.b_i386 and failed
tried /usr/local/lib/pd/extra/expr.b_i386 and failed
tried /usr/local/lib/pd/extra/expr.b_i386 and failed
tried /usr/home/sakae/patch/expr.pd_freebsd and failed
tried /usr/local/lib/pd/extra/expr.pd_freebsd and failed
tried /usr/local/lib/pd/extra/expr.pd_freebsd and failed
tried /usr/home/sakae/patch/expr/expr.b_i386 and failed
tried /usr/local/lib/pd/extra/expr/expr.b_i386 and failed
tried /usr/local/lib/pd/extra/expr/expr.b_i386 and failed
tried /usr/home/sakae/patch/expr/expr.pd_freebsd and failed
tried /usr/local/lib/pd/extra/expr/expr.pd_freebsd and failed
tried /usr/local/lib/pd/extra/expr/expr.pd_freebsd and failed
tried /usr/home/sakae/patch/expr.pd and failed
tried /usr/local/lib/pd/extra/expr.pd and failed
tried /usr/local/lib/pd/extra/expr.pd and failed
tried /usr/home/sakae/patch/expr.pat and failed
tried /usr/local/lib/pd/extra/expr.pat and failed
tried /usr/local/lib/pd/extra/expr.pat and failed
 expr 44100/$f1
... couldn't create

このエラーは何処で出しているのだろう? ソースがあるので検索してみた。本格的に 調べるなら、break pointを置いて、呼び出し経路を調べればいいんだな。

[sakae@cdr ~/pd-0.42-5/src]$ grep 'and failed' *.c
s_path.c:        if (sys_verbose) post("tried %s and failed", dirresult);

ついでなので、もう少し高位のモジュールが出しているであろう、エラーも場所を特定 しておく。エラーって、中を調べて行く時の佳ききっかけになるので、好きだったり します。こういう私は、天邪鬼?

[sakae@cdr ~/pd-0.42-5/src]$ grep "couldn't create" *.c
g_readwrite.c:        error("couldn't create scalar \"%s\"", templatesym->s_name);
g_text.c:            post("... couldn't create");
g_traversal.c:        pd_error(x, "%s: couldn't create scalar", templatesym->s_name);

エラー内容を見ると、pdが期待してる事が分かって面白いなあ。exprを指定しただけで expr.b-i386、expr.pd-freebsd、expr.pdそれにexpr.patと手を変え場所を変えて探し 回ってる。

調べてみたら、/usr/local/lib/pd/extra/expr.pd-linux と言う惜しい名前のファイルが 入っていた。名前をexpr.pd-freebsdにしてあげたら、無事に認識さてくれて動いたよ。 良かったね。

ソースからxx.pd-freebsdを作るには、ソースツリー中にある、extraでそれぞれのmakefile を少々変更してあげる必要がある。FreeBSDのpdの担当マネージャに報告しておこうかな。

AFsp

こうして、何とかパッチが動くようになった。でもこのパッチ、音ファイルを要求するん だよなー。pdに付属してる音ファイルは僅かでしかも再生時間が短すぎて、ちょっとつまらな。 適当な音ファイルはないかなあとあたりを見回してみた。そしたら、昔やったopensolaris に、適当な再生時間のファイルがある事を思い出した。

tried /usr/home/sakae/patch/au-file/spacemusic.au and succeeded
error: soundfiler_read: /usr/home/sakae/patch/au-file/spacemusic.au: unknown or bad header format
... you might be able to track this down from the Find menu.
expr divide by zero detected

折角思い出した、かっこいい音ファイルなんだけど、どうやらそんな特殊な形式のファイル は、扱えないようだ。読み込みに失敗してるにも関わらず、patchが走ってしまうようで、 オマケで割り算エラーも出ているよ。これはもう、特殊形式なファイルをwavあたりの 普通なファイルに変換してあげなければ。。

以前、AFsp を入れておいたので、これを使おう。ついでに、 音ファイルのフォーマット も公開されたのでメモ。

[sakae@cdr ~/patch/au-file]$ InfoAudio spacemusic.au
 AU audio file: /home/sakae/patch/au-file/spacemusic.au
   Number of samples : 48024 (6.003 s)  2009-05-14 15:51:46 UTC
   Sampling frequency: 8000 Hz
   Number of channels: 1 (8-bit mu-law)
File name: spacemusic.au
Header length: 48
Sampling frequency: 8000
No. samples: 48024
No. channels: 1
Data type: mu-law8
File byte order: byte-stream
Host byte order: little-endian
--Information records--
AU info: mood music (loop this)

ふう、サンプルレートが8000Hzってのはいいとして問題は、8-bit mu-lawだなあ。これって 人間の聴覚特性と電話帯域を考慮して、加工や圧縮してたはず。素直にして、サンプルレート も、変換しておこう。

[sakae@cdr ~/patch/au-file]$ ResampAudio -D integer16 -s 44100 spacemusic.au zz.wav
 AU audio file: /home/sakae/patch/au-file/spacemusic.au
   Number of samples : 48024 (6.003 s)  2009-05-14 15:51:46 UTC
   Sampling frequency: 8000 Hz
   Number of channels: 1 (8-bit mu-law)

 Interpolation filter:
   ratio: 24, cutoff: 0.5, alpha: 7.85726, gain = 24
   delay: 816, no. coeffs: 1633, offset: 0, span: 1632

 WAVE file: /home/sakae/patch/au-file/zz.wav
   Sampling frequency: 44100 Hz
   Number of channels: 1 (16-bit integer)
 Sampling ratio: 441/80

これで、普通になったはず。勿論、10倍以上に肥大化しちゃったけど。

[sakae@cdr ~/patch/au-file]$ InfoAudio zz.wav
 WAVE file: /home/sakae/patch/au-file/zz.wav
   Number of samples : 264728 (6.003 s)  2010-04-28 06:17:13 UTC
   Sampling frequency: 44100 Hz
   Number of channels: 1 (16-bit integer)
File name: zz.wav
Header length: 44
Sampling frequency: 44100
No. samples: 264728
No. channels: 1
Data type: integer16
File byte order: little-endian
Host byte order: little-endian
--Information records--
date: 2010-04-28 06:17:13 UTC
program: ResampAudio

このファイルを資料にして実験したら、よく原理が理解出来ました。ちょっとびっくりした のが、配列のINDEXが浮動小数点でも、無問題で動いてしまった事。硬い事は言わないのね。 そうそう、このパッチでは、INDEXがDSPの信号扱いになっているので、普通に数値BOXを 接続しモニターしようとしても、そんな配線は拒否されます。

一度、snapshot~ をかませて、普通の数値に変換してからモニターさせます。勿論、snapshot~ には、bang信号を送ってやらないと、信号を補足してくれません。ついでに、数値を信号に 変換する(snapshotの逆関数)は、sig~ でした。

で、当然と言えば当然なんだけど、再生スピードを変えると、音の高さ(専門用語では、 ピッチと言うそうだ)が変化する。スピードを速くするにつれて、女声から子供の声に 代わり、遅くすると、ドラマでよく出てくる、脅迫電話の声みたいに低く、くぐもった 声になる。従って、誘拐犯にpdを売りつけるといいぞ。

音のプログラミング

件の質問をくれた人の最終目標は多分、モールス信号のスピードを自由自在に速くしたり 遅くしたりして練習したいのだろう。私も同じ事を考えていたので、気持ちは痛い程分かる。

再生スピードを変える事により、モールス信号のトーンと言うかピッチが変わってしまう 事を気にしなければ、十分に事足りるだろう。

でも、トーンが変わってしまうのはイヤダと言うわがままを言われたら、どうしよう。先 回りして調べておくかな。やおら取り出した本は、オーム社発行の【C言語ではじめる音の プログラミング】。これの、11章に音を伸縮する と言うのがあった。

サンプルプログラムは2本あり、一つは再生時間を2/3に縮めるもの、もう一本は、1.5倍に 伸張するものだった。両者共、無問題でFreeBSDでコンパイル実行出来た。

サンプルデータは、男声で ”我輩は猫である。名前はまだ無い。”と言う、有名なフレーズ が録音されていた。縮めるプログラムを通して出来たファイルは、元データの丁度2/3に なっていた。聞いてみると、男声で(ピッチは変わらずに)やけに早口になっていた。 伸張したやつは、超ゆったり気分で朗読してる風になっていた。

本当は、こういうの欲しいんだよねぇ。プログラムの秘密は、C言語で書かれていた、から 読めば分かるっしょ、とは、いかなかった。ええ、説明を読みました友。

解説によると、音データを削れば、縮まるし、データを付け足せた伸張しまっせって事だ。 けど、どこを削る/足す、ばいいかがノウハウになる。

縮める場合なら、3つのデータのうち一つを消せば、データは2つになる。けど、これだと 結局ピッチが変わってしまう。そこで、信号の自己相関をとり、信号の基底周波数を 求め、基底周波数成分レベルで、重ね合わせを行って、縮めている。

言葉では旨く説明できないけど、”あああ”となっていたら(一つの”あ”が、基底周波数と 思ってください)、これを、”ああ” に縮めるイメージ。

最初の”あ”と、二番目の”あ”を、重ねて、一つの”あ”にしてしまい、それに、最後に あった”あ”を続ければ、圧縮した事になる。

しかし、単純に重ねる(デジタル信号上では、足し算)と、そこだけ音が大きくなって しまうので、そうならないように工夫してる。

こういうのって、C言語のレベルで追いかけてみたい。そなら得意のgdbを使えば。。。 まてまて、相手のデータは、配列に入った(連続的な?)データよ。数値で確認してくよりも 、グラフに表示出来た方がいいんでないかい?

昔、ちょっと使った事があるDDD(Data Display Debugger)にでも登場願おうかな。えっと こやつは、gdbのフロントエンドになってて、GUIから操作するようになってたはず。 FreeBSDに入れようとすると、きっとGTKがなんたらかんたらと面倒な事になりそう。 ええい、ArchLinuxで一発インストールだぞ。

幸い有ったよ。偉いぞArchLinuxのポート担当者。で、動かしてみたんだ。けど、肝心の 配列に入ったデータをグラフ化する機能が動かないんだ。ハングアップしちゃうと言うか グラフのグの字も出てこない。グーの音も出ないね。残念、何とかなるかなあ?