Ruby/cdrom Copyright (C) Ueno Katsuhiro 2000 $Id: README-cdrom,v 1.3 2000/12/03 06:21:21 katsu Exp $ == 概要とか Ruby から CD-ROM ドライブを操作するための拡張ライブラリです。 今のところは音楽 CD の再生に偏重していますが、将来的には CD-ROM ドライブ全般を細かく制御できるようにできたらいいな、と 思っていたりいなかったり。 == make とか いつもどおり ruby extconf.rb && make でオッケー。 extconf.rb に --with-default-device オプションを指定することで CDROM::DefaultDevice の値を変更することができます。詳細は後述。 == 対応状況とか ・Linux 多分、こいつの上で動かした時が最も幸せでせう :-) 2.2.17 で動作を確認してます。 Linux 以外の OS への対応については、どなたかにお任せ致します。 ・FreeBSD 阿部洋志さん による FreeBSD のサポート。 詳しくは cdrom-freebsd.txt をご覧下さい。 ・libcdaudio が対応している OS 一応 libcdaudio なラッパーを書きました。 ですが、構造上の違いのために (?) パフォーマンスは激悪です (汗;; また、当然ながらセクタ読み出し系は全滅、ドアロックも不可、 マルチセッションに対応していないので CD EXTRA な CD では 最後の音楽トラックの長さが 2分半ほど長くなったり (ちなみに この 2分半は再生できません) 等々、ネィティブ対応に比べて ディスアドバンテージが天湖森夜となっております(謎) ちょろっと確認した限りでは、CD プレーヤーとしては使えてるようです。 ですが、ワタクシ libcdaudio なんて初めて使うし ほとんどテストしていないというか個人的には必要ないんで あんまり保守する気はありません。 ・Windows (95/98 では動いてるっぽい) rbcd-dance.rb を書いたんで、絵描きな方の協力を得たくて書いたんですが 結局中途半端に終わっちゃいました。なんつっても Windows な プログラミングは久しぶりだし、資料 (MSDN の古いの) はあるものの なぜかその通りに動いてくれないし。 MCI を使っているので、機能的には libcdaudio とほぼ等価です (ボリューム設定はできないが CD EXTRA はバッチリ)。 あと、CD の最後まで再生しきった時のみ CDROM::Status#completed? が 真になります。 というのも、なぜか再生が終了しても MCI_NOTIFY_SUCCESSFUL が送られて こないんですよ。どうあがいても(泣)。もうお手上げっす。 MCI_NOTIFY を使ってほげったコードは #if USE_NOTIFY 〜 #endif で 括ってあります。 ・その他の OS ダミーがあるんでコンパイルは通るのではないかと。 常に長さ 1 のデータトラック 1つだけの CD-ROM が入っているように 見えます。 ・CD チェンジャ? 一応コードは入れてますが。 持ってないので知らぬ存ぜぬ (^^;; == とりあえずマニュアルとか CDROM CD-ROM ドライブを制御するためのクラス。 スーパークラス: Object クラスメソッド: new(device) open(device) device を CD-ROM ドライブとして開く。 メソッド: close 閉じる。 closed? 閉じられているときは真を返す。 path device 開いているデバイスの名前を返す。 inject CD-ROM ドライブのトレイを引っこめる。 eject CD-ROM ドライブのトレイを出す。 lock_door CD-ROM ドライブのトレイの出し入れを禁止する。 ブロックが与えられた場合は、ブロックを実行している間のみロック。 unlock_door CD-ROM ドライブのトレイの出し入れを許可する。 get_tracks TOC を読んで、CDROM::Track オブジェクトの配列を返す。 返される配列の最後の要素は常にリードアウト (Track#leadout? が真) である。また、マルチセッション CD の場合は 各セッションの終わりにリードアウトが現れ得る。 CDROM::Track クラスには、以下のメソッドが定義されている。 track_no トラック番号を返す。リードアウトの場合は -1。 start_addr 開始位置を表す CDROM::Time オブジェクトを返す。 addr 同上。 track_type トラックの種類を表す文字列を返す。 audio_track? 音楽トラック? data_track? データトラック? leadout? リードアウト? size length ディスクのサイズを CDROM::Time オブジェクトで返す。 play_audio([start_addr[, end_addr]]) start_addr から end_addr までを再生する。 start_addr が省略された場合はディスクの先頭から、 end_addr が省略された場合はディスクの最後まで再生する。 引数には、CDROM::Time オブジェクトか 0 以上の整数を与える。 pause_audio ポーズ。 resume_audio ポーズから復帰。 stop_audio 再生を止める。 get_status ドライブの現在の状況を表す CDROM::Status オブジェクトを返す。 CDROM::Status クラスには、以下のメソッドが定義されている。 track_no 再生中のトラック番号を返す。 addr 再生中の絶対位置を表す CDROM::Time オブジェクトを返す。 track_time 再生中の相対位置を表す CDROM::Time オブジェクトを返す。 status 現在の状態を表す文字列を返す。 playing? 再生中? paused? ポーズ中? completed? 再生が終わった no_status? それ以外の状態 get_volume 左右の音量値を含む 2 要素の配列を返す。 音量値は 0 から 255 まで。 set_volume(right[, left]) 音量を設定する。right, left は 0 から 255 まで。 left が省略された場合は right に揃えられる。 num_slots ドライブに入るディスクの数を返す。 change_slot(slot) ディスクを切り替える。slot は nil か 0 以上 num_slots 未満の整数。 slot が nil の時は何もしない。切り替えた後のスロット番号を返す。 current_slot 現在のスロット番号を返す。 ready?([slot]) 指定したスロットにディスクが挿入されており、 すでに操作できる状態にある時に真を返す。 slot が nil の時は現在のスロットを見る。 read_audio(addr[, n]) オーディオデータを addr から n セクタ読み込む。n のデフォルトは 1。 addr は CDROM::Time オブジェクトか 0 以上の整数。 read_mode1(addr[, n]) read_sector(addr[, n]) CD-ROM Mode1 なセクタを読む。 read_mode2(addr[, n]) CD-ROM Mode2 なセクタを読む。 read_raw(addr[, n]) 生読み。 定数: DefaultDevice デフォルトのデバイス名。例えば /dev/cdrom とかが入っているわけで。 extconf.rb の --with-default-device オプションでコンパイル時に 変えることができます。 例外クラス: CDROM::NoDisc Linux には ENOMEDIUM ってエラーがあるんで、それに合わせて 作ってみたりとか。 -- -- -- -- -- CDROM::Time CD-ROM 上のアドレスを表すクラス。LBA と MSF の両方の形式を保持している。 ただし MSF にはオフセットは勘定されていない。つまり、次の等式が成り立つ: <デバイスドライバから得た MSF> - <オフセット(2秒)> = lba = (min * 60 + sec) * 75 + frame スーパークラス: Object インクルードしているモジュール: Comparable クラスメソッド: new(n) セクタ番号 (LBA) n を指す CDROM::Time オブジェクトを返す。 at(second) 先頭から second 秒の位置を指す CDROM::Time オブジェクトを返す。 second は 0 以上の整数または浮動小数点数。 メソッド: self + other 足し算。other は 0 以上の整数か CDROM::Time オブジェクト。 self - other 引き算。 self <=> other 比較。 min MSF の minute の部分を返す。 sec MSF の second の部分を返す。 frame MSF の frame の部分を返す。 to_i LBA を返す。 to_a [ to_i, min, sec, frame ] seconds 先頭からの秒数を浮動小数点数で返す。 real MSF のオフセットを加えた CDROM::Time オブジェクトを返す。 == OS 依存な部分を書く時とか まぁ、なんちゅうか、cdrom.h にズラズラ〜っと書かれている関数を 用意してやればいいわけです。エラーな時は rb_raise とかで 適当に例外投げて下さい。どんな時に何を投げるかについては特に 定めてません。 そのうち必要になったら決めようとか思っていたりいなかったり。 各関数の概要はこんな感じ: void rbcd_open(union rbcd_device *cdrom, const char *device); device を開いて cdrom を初期化。 void rbcd_close(union rbcd_device cdrom); 閉じる。 void rbcd_inject(union rbcd_device cdrom); 吸う。 void rbcd_eject(union rbcd_device cdrom); 吐く。 void rbcd_lock_door(union rbcd_device cdrom, int locked); looked が 0 以外のときロック。0 ならロック解除。 void rbcd_get_track_range(union rbcd_device cdrom, int *start, int *end); トラックの最初の番号を start に、最後の番号を end に返す。 この値の範囲で rbcd_get_track が呼び出される。 void rbcd_get_track(union rbcd_device cdrom, int track_no, struct rbcd_track *track); トラック track_no の情報を track に返す。 struct rbcd_track の track_no メンバは埋めなくても良いです。 start_addr メンバは lba を埋めるか、lba に負の値を入れて msf.min, msf.sec, msf.frame を埋めるかのどちらかで指定して下さい。 void rbcd_get_disc_size(union rbcd_device cdrom, struct rbcd_time *size); ディスクのサイズを返す。 int rbcd_get_last_session_addr(union rbcd_device cdrom, struct rbcd_time *addr); マルチセッション CD の場合、addr に最後のセッションの開始位置を入れて 1 を返す。マルチセッション CD ではない場合やサポートしていない 場合は 0 を返す。 void rbcd_play_audio(union rbcd_device cdrom, struct rbcd_time *start, struct rbcd_time *end); start から end までを再生。 start, end は lba, msf どちらの値も使えます。 void rbcd_pause_audio(union rbcd_device cdrom); ポーズ。 void rbcd_resume_audio(union rbcd_device cdrom); ポーズ解除。 void rbcd_stop_audio(union rbcd_device cdrom); 再生停止。 void rbcd_read_audio(union rbcd_device cdrom, struct rbcd_time *addr, int frames, char *dst); void rbcd_read_mode1(union rbcd_device cdrom, struct rbcd_time *addr, int frames, char *dst); void rbcd_read_mode2(union rbcd_device cdrom, struct rbcd_time *addr, int frames, char *dst); void rbcd_read_raw(union rbcd_device cdrom, struct rbcd_time *addr, int frames, char *dst); セクタ読み出し系関数。addr から frames セクタを dst に読み込む。 addr は lba, msf どちらの値も使えます。 frames きっかり読めなかったら例外投げちゃっていいよね? void rbcd_get_status(union rbcd_device cdrom, struct rbcd_status *status); 現在のドライブの状態を status に返す。 addr メンバへの値の入れ方は rbcd_get_track 参照。 void rbcd_get_volume(union rbcd_device cdrom, int *left, int *right); 現在の音量を left, right に返す。left, right 共に 0 以上 255 以下。 void rbcd_set_volume(union rbcd_device cdrom, int left, int right); 音量を設定する。left, right 共に 0 以上 255 以下。 int rbcd_num_slots(union rbcd_device cdrom); 入るディスクの枚数。CD チェンジャでない場合は 1 を返すこと。 int rbcd_change_slot(union rbcd_device cdrom, int slot); ディスクの切り替え。slot は 0 以上 rbcd_num_slots() 未満の整数。 切り替え後のスロット番号を返す。 slot が負の場合は、何もせずに現在のスロット番号を返す。 int rbcd_is_ready(union rbcd_device cdrom, int slot); slot が準備できているなら 0 以外。でなければ 0。 slot は 0 以上 rbcd_num_slots() 未満の整数。 slot が負の場合は現在のスロットを見る。 ----