Allegroで Ogg Vorbis ファイルを再生する。

  今回は、OSX上でAllegroによるOgg Vorbis 音源を再生に挑戦してみた。
が、どうもOSXでは サウンド関係の相性が良くない(自分のやり方が間違ってるのかもしれない)。
再生には失敗したが、今後のバージョンアップによりOSX での動作が改善されることを期待して、
API などのメモを残すことにした。

OSX&Allegro での結果
それぞれコンパイルとインストールには成功した。


APEG    :OggVorbis 再生成功 (他にはMPEG再生などの機能がある)
AllegroOgg :OggVorbis 再生失敗。ファイルを読み込むがノイズしか聞こえない
        ( 用意されたAPI が使いやすいのが特徴)
DUMB   :OggVorbis 再生失敗 その他のフォーマット再生も失敗)
        (Ogg Vorbis は 別のファイルからインストールする)
 
(ogg を使うには、あらかじめ libogg-1.1.2、 libvorbis-1.0.1 libtheora の順でインストールする必要がある。)
 
 
(04.01 APEG での apeg_play_mpg関数による Ogg Vorbis 再生に成功)
(03.31 Allegro Ogg による再生は失敗 。データは再生しているようだが、ノイズしか聞こえない状態。)
alogg_Folder/examples のサンプルコードでもノイズ ..。

Allegro ogg の関数

(結局、再生に失敗したので、行なった事だけを書いてあります)
http://nekros.freeshell.org/delirium/alogg.php
からalogg.zipをダウンロードして解凍。alogg_Folderを開く。

makefile をOSX 用に 少し書き換える。
ターゲット は LINUX_STATIC のを借用

# MACOSX_STATIC
ifeq ($(TARGET),LINUX_STATIC)
TARGETFLAGS=-W -Wall -O2 -c -s -ffast-math -fomit-frame-pointer -finline-functions
OBJDIR=obj/linux/static
LIBDEST=lib/linux/libalogg.a
endif
を LINUX_STATIC のif 部分の下にでも書き加えてmakefileを保存。

ターミナルから、alogg_Folder へ移動して
./fixunix.sh
make
すると libalogg.a というファイルが alogg_Folder/lib/linux の内にできているので、
それ を /usr/local/lib へ入れる。

alogg_Folder/include 内 にある alogg.h と aloggdll.h(これも必要らしい) を
/usr/local/include へ入れる。

xcodeのリンカ設定、その他のリンクフラグに、 -lalogg を追加。
ソースに、 #include を書き加える。

alogg_Folder/examples にサンプルコードがあるのでそれも参考になると思う。



Alogg メモ
Alogg での ogg vorbis の再生方法は3つあって、

1) Using ALOGG_OGG and alogg_create_ogg_from_file()
を使えば .oggファイルから少しづつデータを再生する。

2) Using ALOGG_OGG and alogg_create_ogg_from_buffer()
の組み合わせだと、メモリバッファ上のデータを再生する。

3) Using ALOGG_OGGSTREAM
ストリーム再生 ファイル全体メモリ上に読み込む 必要に応じてデータの固まりをよこす。
(例えば、ネットワーク上からデータを再生する等)


1) の方法で ファイルを読み込む
ALOGG_OGG *alogg_create_ogg_from_file(FILE *f);
FILE *f というのは、ファイルポインタであることに注意。
あらかじめ FILE *oggfile; oggfile = fopen("sample.ogg", "r"); などと取得しておく必要がある。

#include <stdio.h >
FILE *oggfile;
ALOGG_OGG *oggsound;

oggfile = fopen("./BGM009.ogg", "r" );
oggsound = alogg_create_ogg_from_file(oggfile);

alogg_play_ogg( oggsound , 32768, 180 ,127);

2) の方法 データのポインタを渡して、メモリ上のデータを読む。 data_len はデータの長さ。
ALOGG_OGG *alogg_create_ogg_from_buffer(void *data, int data_len);
void *data, int data_len


ALOGG_OGG *alogg_destroy_ogg(ALOGG_OGG *ogg);
データを使い終わったらメモリを解放
もし、ogg ファイルが存在しない場合、 alogg_create_ogg_from_f が NULL を返した場合
すぐに、destroy_ogg を呼べば プログラムのクラッシュを回避できる。
ALOGG_OGG *oggsound = NULL;
alogg_destroy_ogg(oggsound);
1) 2) 3) でいずれかの 方法で読み込んだデータを再生するには
int alogg_play_ogg(ALOGG_OGG *ogg, int buffer_len, int vol, int pan);

関数を利用する。
音の大きさ int vol は 0〜255 の値を取る。
パン int pan は 左側 0〜255 右側からの音が強く反映される
( pan = 127 の場合は、中央方向からバランスよく再生される)
バッファ buffer_len にはデコードされたデータが蓄えられる。
しかし、この値が大きすぎると曲が始まるまで長く待たなければならない。
たいていは16kb = 16384 or、32kb= 32768 の値がよく使われる
alogg_play_ogg( oggsound , 32768, 80 ,127);
返値
ALOGG_OK 問題ない
ALOGG_PLAY_BUFFERTOOSMALL バッファを大きくする必要がある。

この関数には、リジューム機能があって、一時停止 しても ALOGGオブジェクトの データ を巻き戻さない。
曲の終わりに達すると「自動的」に、最初に巻き戻され、エンコードを停止する。
なお、loop flag が FALSE or Continue の場合( alogg_play_ex_ogg() 参照)の場合はそれに従う。

int alogg_play_ex_ogg(ALOGG_OGG *ogg, int buffer_len, int vol, int pan, int speed, int loop);
上の関数の拡張版、 再生スピード と ループフラグが追加されている。
再生スビード speed = 1000 通常再生 , 2000 二倍速再生 , 500 スロー再生
ループフラグは、曲の終わりに達したら再生をやめるかどうかを指定することができる。

void alogg_stop_ogg(ALOGG_OGG *ogg);
 もし 再生している場合は、再生を停止する。いわゆる一時停止。
 再び再生する場合は、また alogg_play_ogg やalogg_play_ex_oggを呼び出す。

void alogg_rewind_ogg(ALOGG_OGG *ogg);
曲の最初に巻き戻す。ただし曲の再生中はこの関数は機能しない。


void alogg_seek_abs_msecs_ogg(ALOGG_OGG *ogg, int msecs);
void alogg_seek_abs_secs_ogg(ALOGG_OGG *ogg, int secs);
void alogg_seek_abs_bytes_ogg(ALOGG_OGG *ogg, int bytes);

再生位置の指定(絶対位置)

void alogg_seek_rel_msecs_ogg(ALOGG_OGG *ogg, int msec);
void alogg_seek_rel_secs_ogg(ALOGG_OGG *ogg, int sec);
void alogg_seek_rel_bytes_ogg(ALOGG_OGG *ogg, int bytes);

再生位置の指定 (相対位置)
これらの関数を曲の再生中に呼び出しても、曲は停止しない。


int alogg_poll_ogg(ALOGG_OGG *ogg);
この関数を呼び出した時に、再生中のプロパティ(状態)を取得できる
ただし、得た情報は、関数が呼び出された時点のものであることに注意する。
返値
ALOGG_OK 問題なし
ALOGG_POLL_PLAYJUSTFINISHED 再生終了
ALOGG_POLL_NOTPLAYING 再生されてない
ALOGG_POLL_FRAMECORRUPT フレームが壊れている
ALOGG_POLL_INTERNALERROR 内部エラーが発生

void alogg_start_autopoll_ogg(ALOGG_OGG *ogg, int speed);
int speed で指定した間隔で定期的に pollingする。
プログラムの仕様上、一定の間隔で呼ぶことができない場合にはこの関数を利用できる。

int alogg_get_bitrate_ogg(ALOGG_OGG *ogg);
ビットレートを返す。例えば128000, 64000, 96000 bps (kbit ではないので注意)


int alogg_get_pos_msecs_ogg(ALOGG_OGG *ogg);
int alogg_get_pos_secs_ogg(ALOGG_OGG *ogg);
int alogg_get_pos_bytes_ogg(ALOGG_OGG *ogg);

現在再生されているデータの位置を、秒、ミリ秒、byte数で 返す。

int alogg_get_length_secs_ogg(ALOGG_OGG *ogg);
int alogg_get_length_msecs_ogg(ALOGG_OGG *ogg);
int alogg_get_length_bytes_ogg(ALOGG_OGG *ogg);

再生するデータの大きさを、秒、ミリ秒、byte数で 返す。
曲の長さを求める場合に使う。


int alogg_get_wave_bits_ogg(ALOGG_OGG *ogg);
int alogg_get_wave_is_stereo_ogg(ALOGG_OGG *ogg);
int alogg_get_wave_freq_ogg(ALOGG_OGG *ogg);

波形に関する情報を返す。


int alogg_is_playing_ogg(ALOGG_OGG *ogg);
再生されているかどうかを返す。
返値
TRUE 再生中
FALSE 再生されていない


int alogg_is_looping_ogg(ALOGG_OGG *ogg);
void alogg_set_loop_ogg(ALOGG_OGG *ogg, int loop);

ループしているかどうかを調べる関数と、ループフラグをセットする関数
これらの関数は、再生中にしか機能しない。

void *alogg_get_output_wave_ogg(ALOGG_OGG *ogg, int *buffer_size);
poll した後 にデコードした波形から、バッファサイズぶんのデータを出力する。
16 ビット・データ標準形式の代りにunsinged Allegro のフォーマットを使用する。
また、この関数は呼び出された時しか出力しないので注意。

返値
NULL なにもデコードされtない
それ以外は、バッファに wave dataが記録される。

以下、alogg stream の解説があるが割愛。

APEG を使ってみる。


APEG は、 Allegro で MPEG や ogg theora/Vorbis を再生する拡張ライブラリである。
http://kcat.strangesoft.net/

APEG_STREAM *apeg_open_stream(const char *filename, int buffer_size);
void apeg_close_stream(APEG_STREAM *stream);
int apeg_start_audio(APEG_STREAM *stream, int start);

APEGをインストールする前に注意する。
ogg.c でogg.h vorbis/codec.h theora.hファイルが include されるため
あらかじめ libogg-1.1.2、 libvorbis-1.0.1 libtheora の順でインストールしておかないと、
エラーが出てコンパイルできない
ogg theora は http://www.theora.org/ でダウンロードできる。
それぞれ、 ./configure , make , sudo make install する 。

AlegOgg に収録されている ogg は 1.0.0.1なので、最新版theora では、チェックによって 弾かれてしまうので注意。
chmod +x fix.sh
./fix.sh osx
make
さらに、make中にエラーが発生したため、 makefile.all で、ar d lib/libapeg.a * する部分の原因
makefile.all にある ar d $(LIB_NAME) * という行を コメントアウトする。アーカイブ化に成功
しかしなぜか sudo make install が失敗したので、libapeg.a と apeg.h をそれぞれ手動で入れることにした。

コンパイルのリンカフラグには -lalleg の前に必ず, -logg -lvorbis -ltheora -lapeg のオプションを追加しておく
(音源のみ再生する場合でも)。これを忘れるとコンパイルに失敗する。

#include <apeg.h>
も、追加しておく。

OSXではlibogg.0.dylib is not preboundsなどのエラーが出るがコンパイルできる。

APEG_STREAM *stream;
stream = apeg_play_mpg("BGM.ogg", NULL , FALSE, NULL);

で、Ogg Vorbis形式のファイルを再生。
APEG でも、Ogg Vorbis の再生 はできますが、
AleOgg のように 再生 秒数など細かい情報 は取得できないようだ(未実装?)。


構造体の説明。
typedef struct APEG_STREAM {
BITMAP *bitmap; // デコードされた映像が表示される BITMAPオブジェクト
int frame_updated; // 0 なら スキップされる。正なら更新されている。負なら もう表示されるフレームがないことを示す。

int frame; // 現在再生されているフレームの番号

int w, h; // 再生される映像の幅と高さ
float aspect_ratio; // アスペクト比
enum pixel_format; // ビデオストリームのエンコードフォーマット
// will be set to APEG_420, APEG_422 (Theora only), or
// APEG_444 (Theora only)

float frame_rate; // フレームレート
LONG_LONG bit_rate; // ビットレート

volatile int timer; // タイマー フレームが表示されるまでにカウントされる

int flags; // ストリームに関するなにかの情報を含む
APEG_AUDIO_INF audio; // オーディオストリームに関する構造を含む
// information
} APEG_STREAM;
int kbps; // 再生される音声のbps
int layer; // 現在再生されている レイヤーのバージョン(Mpeg-3 Layer 等)
int freq; // ストリームの周波数
int down_sample; // ダウンサンプリングモード (0=1:1, 1=2:1, 2=4:1)
int channels; // プレイバックチャンネルカウント
int down_channel; //真ならば playback が down channeledされた事を示す。
} APEG_AUDIO_INF;

読み込み
ファイルやデータの読み込みには3つのタイプがある
APEG_STREAM *apeg_open_stream(const char *filename, int buffer_size);
ファイル名&バッファサイズを指定して oggMpegを読み込む

APEG_STREAM *apeg_open_memory_stream(void *mpeg_data, int data_len);
メモリ上にあるmpegデータへのポインタを指定することで、それを読み込む。

APEG_STREAM *apeg_open_stream_ex(void *ptr);
 ストリーム形式で読み込む。


関数
int apeg_advance_stream(APEG_STREAM *stream, int loop);
もしビデオを扱うなら、先に、オーディオ部分がデコードされる。
VideoSync にあわせて定期的に、ビデオ部分がデコードされる。
異常が発生した場合は、APEG_ERROR が返される。
正常なら、APEG_OKを返し、再生が終了すると APEG_EOF を返す。

void apeg_close_stream(APEG_STREAM *stream);
APEG_STREAM を閉じる。


int apeg_enable_video(APEG_STREAM *stream, int enable);
システム固有の ビデオエンコード機能を有効/無効にする。
もしあなたが望むなら、MPEG からオーディオあるいはビデオ部分のみを再生することができる。
int enable = 1 or NULL

int apeg_start_audio(APEG_STREAM *stream, int start);


int apeg_play_mpg(const char *filename, BITMAP *bmp, int loop, int (*callback)());
int apeg_play_memory_mpg(void *mpeg_data, BITMAP *bmp, int loop, int (*callback)());

ファイルかメモリ上から mpeg データを読む。 ループ再生フラグと、コールバック機能がついている。
映像は、指定した BITMAPオブジェクトの左上に表示される。
返り値が APEG_OK なら正常 APEG_ERROR なら何かエラーが発生したという意味。
コールバックがNULLの場合、再生が終了するか何かキーが押されない限り、プログラムは進行しない。

例:コールバック 
int test(void ){ return 0; } という関数を作っておいて、 callback に test()関数を指定する。
stream = apeg_play_mpg("BGM.ogg", tekito , FALSE, test );
test(); //この関数が呼ばれたときに、apeg_play_mpg()が呼ばれ、BGM.ogg が再生される。
コールバックには main 関数を指定しないこと。



例:ファイル再生
APEG_STREAM *stream;
stream = apeg_play_mpg("BGM.ogg", NULL , FALSE, NULL);



DUMB 0.9.2

IT, XM, S3M, MODファイルを再生することができるライブラリ。
http://switch.dl.sourceforge.net/sourceforge/dumb/dumb-0.9.2-fixed.tar.gz
をダウンロードして展開。IT形式のファイルの再生はfmod よりもよいとか?
 
cd dumb make config Would you like support for Allegro (Y/N)? Y make sudo make install cp lib/unix/libdumb.a /usr/local/lib cp lib/unix/libdumbd.a /usr/local/lib cp examples/dumbout /usr/local/bin cp include/dumb.h /usr/local/include cp lib/unix/libaldmb.a /usr/local/lib cp lib/unix/libaldmd.a /usr/local/lib cp examples/dumbplay /usr/local/bin cp include/aldumb.h /usr/local/include DUMB has been installed. See readme.txt for details on the example programs. When you're ready to start using DUMB, see docs/howto.txt. Enjoy!
サンプルプログラム dumbplay Allegro を利用して動作する。 IT, XM, S3M or MOD ファイルの再生。 dumbout Allegroは不要。IT, XM, S3M or MOD ファイルのストリーミング再生 DUMBの使い方 #include <aldumb.h> Xcode で コンパイルする時のリンク  Allegroライブラリを利用する場合 :-laldmd -ldumbd Allegroライブラリを利用しない場合: -ldumbd Allegro で使うには まず、Allegro をallegro_init() の下に、atexit(&dumb_exit); という関数書いておく。 この関数を書いておけば、プログラムが途中で中断してもDUMB用メモリが自動的に解放されるようになる。
allegro_init(); atexit(&dumb_exit);
それから、音源の初期化をしておく。 install_sound(DIGI_AUTODETECT, MIDI_NONE, NULL); 曲データを格納するDUH ストラクチャを用意する。 DUH *myduh; それぞれのフォーマットの曲ファイルを読み込む myduh = dumb_load_it("a_one.it"); myduh = dumb_load_xm("a_two.xm"); myduh = dumb_load_s3m("a_one_two.s3m"); myduh = dumb_load_mod("three_four.mod"); プログラムを終了させる場合は その前にメモリを解放しておく。 unload_duh(myduh); 曲データを再生するには AL_DUH_PLAYER ストラクチャを用意する。 AL_DUH_PLAYER *dp; AL_DUH_PLAYER *al_start_duh(DUH *duh, int n_channels, long pos, float volume, long bufsize, int freq); 再生する。 'n_channels' は、1=モノラル / 2=ステレオ で指定する。 'pos' 0=曲の始まり / 65536 を加えるたびに次の部分へ進行する volume' はとりあえず 1.0f にしとく。 'bufsize' バッファサイズ=4096 がよいらしい。 ' freq ' 周波数 44100 (44kHz)あるいは 48000 (48kHz)  void al_stop_duh(AL_DUH_PLAYER *dp); al_stop_duh()関数: 音楽の停止は、AL_DUH_PLAYER ストラクチャ に対して行われる。 また、 unload_duh() する前には必ずal_stop_duh()を呼び出しておく。 int al_poll_duh(AL_DUH_PLAYER *dp); 再生中の音楽データのポーリング AL_DUH_PLAYER ストラクチャに対して行われる。 注意:この関数は timer function からは呼び出してはいけない。 どのくらいの割合でこの関数を呼び出せばいいかは、 al_start_duh()で指定した ' bufsize ' に左右される。 n = freq / bufsize; API void al_pause_duh(AL_DUH_PLAYER *dp); void al_resume_duh(AL_DUH_PLAYER *dp); void al_duh_set_volume(AL_DUH_PLAYER *dp, float volume); long al_duh_get_position(AL_DUH_PLAYER *dp); long duh_get_length(DUH *duh); それぞれ、一時停止、一時停止の解除(リジューム)、音量のセット、再生位置の取得、音楽データの長さの取得 ループまたは音楽のフリーズを行う IT, XM, S3M, MODファイルに適用される。 void dumb_it_set_loop_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data); void dumb_it_set_xm_speed_zero_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data), void *data); int dumb_it_callback_terminate(void *data);
 コードの例:
{ DUH_SIGRENDERER *sr = al_duh_get_sigrenderer(dp); DUMB_IT_SIGRENDERER *itsr = duh_get_it_sigrenderer(sigrenderer); dumb_it_set_loop_callback(itsr, &dumb_it_callback_terminate, NULL); dumb_it_set_xm_speed_zero_callback (itsr, &dumb_it_callback_terminate, NULL); }
このコードを実行すると  al_poll_duh() の返り値が重要になってくる。音楽データが再生されている場合は 0 を返すが 音楽が停止すると、al_poll_duh() は非ゼロを返す。 al_poll_duh() を再び呼ばない限りは、あなたは望むときに、al_stop_duh() を呼び出して音楽を停止することができる。 al_poll_duh() が 1 を返す場合はメモリが足りないか、 音楽データがロードされていない事を示す。 もし、 もう一度 loop や freeze したければ&dumb_it_callback_terminate の代わりに NULL を置くと元に戻す事ができる。 typedef void (*DUH_SIGRENDERER_ANALYSER_CALLBACK)(void *data, const sample_t *const *samples, int n_channels, long length); void duh_sigrenderer_set_analyser_callback(DUH_SIGRENDERER *sigrenderer, DUH_SIGRENDERER_ANALYSER_CALLBACK callback, void *data) void dumb_it_set_midi_callback(DUMB_IT_SIGRENDERER *sigrenderer, int (*callback)(void *data, int channel, unsigned char byte), void *data); int dumb_it_callback_midi_block(void *data, int channel, unsigned char byte); と   Embedding music files in Allegro datafiles  

DUMB OGG0.5

DUMBで Ogg Vorbis を再生することができるようになる。 http://nchc.dl.sourceforge.net/sourceforge/dumb/dumbogg-0.5.tar.gz dumbogg/make/makefile.uni を書き換える。 一番始めにある OFLAGS = -mcpu=pentium -O2 -fomit-frame-pointer -ffast-math から、-mcpu=pentium というオプションを削除。
cd dumbogg ./fix.sh unix make
ld: table of contents for archive: /usr/local/lib/libaldmb.a is out of date; rerun ranlib(1) (can't load from it) ld: table of contents for archive: /usr/local/lib/libdumb.a is out of date; rerun ranlib(1) (can't load from it) というエラーメッセージが出る場合は ranlib してアーカイブを有効にすると改善される。
sudo ranlib /usr/local/lib/libdumbd.a sudo ranlib /usr/local/lib/libaldmd.a
  手動でファイルをインストールする場合は  dumbogg/lib/unix/libdmogg.a をusr/local/bin に  dumbogg/include/ldumbogg.h を usr/local/include に コピー ヘッダは #include #include リンカの設定は -ldmogg -laldmd -ldumbd でよいそうなんだが、 alleogg:0: Undefined symbols: _ov_bitrate _ov_clear _ov_info _ov_open _ov_pcm_seek _ov_pcm_total _ov_read_float _ov_time_total というエラーがでるので、ogg 関係のものをリンクする事にした -L/usr/local/lib -lalleg-main -ldmogg -laldmd -ldumbd -lvorbisfile -lvorbisenc -lvorbis -logg

Tsukubado