Haskellの憎き ...

女房が安売りしてたと言う、パセリを山のように買ってきた。一山80円だったとか。 本当に山のようにと言うか、大きな杉玉ぐらいあるやつだ。こんなにあるなら、 パセリが主役な料理って無いものか? 早速、調査を命じられましたよ。

料理するならクックパッドで調べてみたけど、この80円玉 を1回で使い切る事が出来そうなものは見つからなかった。ええ、それで、責任取って 、塩を振りかけながら食べましたとも。余ったものは、家で一番大きいタッパーに ギュウギュウ詰めにして、冷凍庫に保管されました。

どうでもいい事だけど、このサイトRailsで構築されてるとか、サーバーは Mongrel 1.1.5 だそうです。

Haskellの憎き ...

そうなんです。以前からの宿題にしていた、音ファイルの解析なんですが、プログラム を書き始めたのはいいのですが、躓いています。

そう、IO a と言う奴に阻まれて、さっぱり前へ進めません。勉強不足は認めますが すらすらと進まないと、気持ちが萎えます。今回は音ファイルと言う事で、バイナリーを 扱う事になりますんで、資料が乏しいのも一因かも知れません。

このあたりをじっくり見て手を 動かしながらですかね。それともProgramming in Haskell で、やり直しでしょうか?

Gaucheで書いて、元気になろう

柔軟で、いろいろな便利機能が取り込まれている、gaucheなら 自由奔放?に書ける だろう。で、書いてみた。

(use binary.io)
(use binary.pack)
(use util.match)

(define sound-file "/home/sakae/wave/onVMWARE")
;(define sound-file "/home/sakae/wave/fromWin")

(define M '())         ; For Mono
(define L '())         ; For Stereo Left
(define R '())         ; For Stereo Right

(define (makeM fp func n)
  (dotimes (i n)
    (set! M (cons (func fp) M)))
  (set! M (reverse M)))

(define (makeS fp func n)
  (dotimes (i n)
    (set! L (cons (func fp) L))
    (set! R (cons (func fp) R)))
  (set! L (reverse L))
  (set! R (reverse R)))

(define (getV temp fp pos)
  (port-seek fp pos SEEK_SET)
  (car (unpack temp :input fp)))

(define (wave-info file)
  (let* ([fp (open-input-file file)]
	 [ms (if (= 1 (getV "s" fp 22)) 'Mono 'Stereo)]	; Mono or Stereo
	 [hz (getV "i" fp 24)]		                ; Sampling Freq
	 [bit(getV "s" fp 34)]		                ; 8 or 16Bit
	 [size (if (string=? "data" (getV "A4" fp 36))  ; Data size in Byte
		   (getV "l" fp 40) (getV "l" fp 54))])
    (format #t "~a ~a ~a  ~a\n" ms hz bit size)
    (match (cons ms bit)
      [('Stereo . 16) (makeS fp read-s16 (/ size 4))]
      [('Stereo .  8) (makeS fp read-s8  (/ size 2))]
      [('Mono   . 16) (makeM fp read-s16 (/ size 2))]
      [('Mono   .  8) (makeM fp read-s8  size)])
    (close-input-port fp)))

ファイルのmagicは面倒なので、見てません。エラーチェックもさぼってます。 Haskellやってて、schemeにもあればいいなあと思っていたパターンマッチ機能、 shiroさんはちゃんと用意してくれてました。infoをあちこち読んでたら、Haskell から輸入しましたって機能が他にも有り、ああ、nobsunの影響かな、と。 rubyにも、こういう面白い事やってる方が おられるのね。メアドからドイツの人っぽいけど。

gosh> (wave-info sound-file)
Mono 22050 16  441000
#<undef>
gosh> (length M)
220500
gosh> (apply max M)
16422
gosh> (apply min M)
-16423
gosh> (use srfi-1)
#<undef>
gosh> (length (filter (lambda (v) (> v 10000)) M))
3877
gosh> (length (memv 0 M))
211175

大体、動いてるっぽい。後は、解析用の関数を書いていくだけだな。

おまけ

上記の例では、サンプリング周波数が、22050Hz(周期にすると45.3マイクロ秒)で 行われている。やけに半端な周波数だなあ。しかも、これが業界の標準規格だそうだ。 音本によると、この規格は、ビデオテープに音データを記録する装置の開発から生まれたとの事。

ビデオテープは、525本の走査線x30フレームの構成になっている。この525本の走査線 から、490本を選び、1走査線内に3回のサンプリングデータを記録する事にしたそうな。 そうすると、

3 x 490 x 30 = 44.1KHz

これが、CDの場合のサンプリング周波数にも流用されたとか。22050Hzは、CDほど 音質が良くなくてもいいべと某連合が寄り集まって決めた。(CD音質の半分です。)

パソコンで、モスキート音は、ちゃんと録音・再生出来るのだろうか? 勿論、音 カードを入れれば大丈夫でしょうが。そういう投資をしない場合??かなあ。

まあ、私の場合、耳のf特が落ちてますから、無理ですが。。。