2008年1月21日月曜日

Chapter 25 Practical: An ID3 Parser

前説

  • ID3v2.2とID3v2.3を実装対象とする。



Structure of an ID3v2 Tag

うーん。こういうところも、図表も付けてくれた方がわかりやすいと思うのだが。意図あるのかな?
メモ。

  • A tag は、a headerではじまる。
  • そのheaderは、そのtagの概要情報を含む。a headerとは次の整列ルールをもっている。

    • 3B : 文字列"ID3"。(ISO-8859-1 characters, 73,68,51)
    • 2B : ID3のメジャーバージョンとリビジョン。ただしメジャーバージョンは実はマイナーバージョンの格納に使われている。なので、ID3v2.3の場合、メジャーバージョンには3が入る。リビジョンは、現状は0しか運用されていない。
    • 1B : ビットフラグ。このビットフラグの意味はID3のバージョンによって異なる。このビットフラグは、これ以降の構造の切り替えフラグにもなっている。
    • 4B : an integer。ただし、それぞれのByteのうち7bitsしかつかわない。これはタグのサイズを表す(headerは除く)。

  • v2.3では、この後に several extended headerが来ることができる。
  • その後は、framesがくる。framesにはいくつか種類があり様々な情報を格納できる。a frameの構造は、

    • a header から始まる。
    • a header は a string identifierとa sizeを含む。v2.3では、それに続き2Bのフラグがあり、はじめの1Bの値によっては、2つめの1Bは暗号方式の指定であり、the frameの残りの部分の復号に使用される。



あと、framesがいくつ含まれるかは読まないと分からないということ。framesの中身はnull bytesを含むことがあり、搬送している情報のサイズと同じとは限らないこと。などなど。

なるほど。Practicalな題材だ。


Defining a Package

この本、パッケージを利用するときは、エクポートするシンボルを初めから一覧にしちゃってるんですね。そこを足したり引いたりしながら作っていくようなプロセスも見せてもらえれば参考になるんですが。まあ自分でやれってことでしょう。


Integer Types

define-binary-typeの復習。

  • マクロ。
  • read-value methodとwrite-value methodを生成する。
  • それらはCLの組み込みclassesに対するもの。define-binary-classに対するものではない。
  • 次のものを入力として受けとる。

    • the name of the type
    • the &key parameters (the read-valueとthe write-valueメソッドが受け取る情報)
    • the code for reading from a stream
    • the code for writing to a stream

  • これらを受け取ったマクロは、総称関数であるread-value,write-valueにそれらを入力型とするメソッドを登録する。
  • もうひとつ、short formsというのもこのマクロは対応している。
  • それは、すでに定義済みのread-valueメソッドをもとに、より特定化されたread-valueを作るためのもの。
  • 例えば、(define-binary-type u1 () (unsigned-integer :bytes 1))とか。


このまんまで、u1〜u4は定義可能。しかし、ID3タグサイズは4Byteだが、それぞれのByteでは下位7bitsしか使わず、それによって、28bitsをあらわしている。これはLDBのsizeで対応すると。それを&keyで受けとるように調整して、u1〜u4とid3-tag-sizeを統一的に記述できると。なるほど、やっと前章の意味が理解できてきた。


String Types

特になし。


ID3 Tag Header

う、MP3のファイルをまったく持ってない。落とす。
奏サウンド
Foot Loose
日本語のものの曲名がiTunes上で文字化けしている。大丈夫なのかな。

ううむ。show-tag-headerは動くが、show-tag-headersが動かない。とりあえず放置。


ID3 Frames

もんもんとしてるだけで、頭に入らない。。。メモ。


  • id3-frameの定義にdefine-tagged-binary-classを使う。dispatch関数は、find-frame-classとする。

    (define-tagged-binary-class id3-frame ()
    ((id (iso-8859-1-string :length 3))
    (size u3))
    (:dispatch (find-frame-class id)))

  • framesの種類は、24はある。
  • そこでまずgeneric frame classから作る。
  • これで取り敢えずframeを読めるようになる。24種類あるけど実際に使われているのは数種類と予測されるのでそれを調べる。
  • generic frameはid3-frameのサブクラスとする。

    (define-binary-class generic-frame (id3-frame)
    ((data (raw-bytes :size size))))

  • raw-bytesは新しい型。単にan array of bytesとして情報を保持するだけ。定義する。

    (define-binary-type raw-bytes (size)
    (:reader (in)
    (let ((buf (make-array size :element-type '(unsigned-byte 8))))
    (read-sequence buf in)
    buf))
    (:writer (out buf)
    (write-sequence buf out)))

  • find-frame-classはとりあえず'generic-frameのみ返すようにしておく。

    (defun find-frame-class (id)
    (declare (ignore id))
    'generic-frame)

  • ここまで整備できたので、id3-tagにid3-framesというbinary typeを追加したい。
  • これにはframe領域にあらわれるpadding bytesの処理の実装が必要。
  • id3-framesは、paddingは読みとばし、frame objectsをみつけたら生成するという役割を担う。

    (define-binary-type id3-frames (tag-size)
    (:reader (in)
    (loop with to-read = tag-size
    while (plusp to-read)
    for frame = (read-frame in)
    while frame
    do (decf to-read (+ 6 (size frame)))
    collect frame
    finally (loop repeat (1- to-read) do (read-byte in))))
    (:writer (out frames)
    (loop with to-write = tag-size
    for frame in frames
    do (write-value 'id3-frame out frame)
    (decf to-write (+ 6 (size frame)))
    finally (loop repeat to-write do (write-byte 0 out)))))

    ※(size frame)はアクセサーによるアクセス。


Detecting Tag Padding

read-frameを作る。ここで、condition systemを使う。これはunwindさせるので、exceptionと同じですね。


Supporting Multiple Versions of ID3
Versioned Frame Base Classes
Versioned Concrete Frame Classes
What Frames Do You Actually Need?
Text Information Frames
Comment Frames
Extracting Information from an ID3 Tag

後半は、特になし。前半を理解するのに時間がかかりました。前半は、前章を復習しながらナントカでした。
tagged binaryってどの程度使われているのでしょうか。名前からしてTIFFとかはそうかもしれません。

0 件のコメント: