OpenALでwavファイルのストリーム再生をしてみた。 前回作成したリングバッファクラスやストリームクラスを使用していません。 今回はOpenALで作ったサンプルプログラムです。 手抜き実装のためwavファイルのフォーマットが8ビットの場合は再生できません。
Windows版はWindowsXP SP2でMacOSXは10.5.5で動作確認した。 ソースファイルについては以下の通り。 Windows版はVisualStudio.NET2003用のWin32コンソールプロジェクト。 MacOSX版はXcode3.0のCommandLineUtilityのC++Toolプロジェクト。
#include "stdafx.h" #include <windows.h> #include "standard.h" #include "OpenAL/include/al.h" #include "OpenAL/include/alc.h" #pragma comment(lib, "OpenAL/libs/Win32/OpenAL32.lib") static const ALint BUFFER_MAX = 4; static const size_t DATA_SAMPLE_MAX = 44100 * 2; #pragma pack(push, 1) struct RiffHeader { uint32_t riff; uint32_t size; uint32_t type; }; struct Chank { uint32_t id; uint32_t size; }; struct Fmt { uint16_t format_id; uint16_t channel; uint32_t sampls_per_sec; uint32_t average_bytes_per_sec; uint16_t block_size; uint16_t extension_size; uint8_t extension[1]; }; #pragma pack(pop) int _tmain(int argc, _TCHAR* argv[]) { if(argc < 2) { exit(-1); } // waveファイル読み込み FILE* file; file = _tfopen(argv[1], _T("rb")); if(file == NULL) { exit(-1); } // waveヘッダ解析 RiffHeader header; fread(&header, 1, sizeof(RiffHeader), file); if((header.riff != 'FFIR') || (header.type != 'EVAW')) { fclose(file); exit(-1); } // waveチャンク解析 uint32_t channel = 0; uint32_t sampls_per_sec = 0; Chank chank; Fmt* fmt = NULL; for(;;) { if(fread(&chank, 1, sizeof(Chank), file) == 0) { fclose(file); exit(-1); } if(chank.id == 'atad') { // dataチャンクなら終了 break; } else if(chank.id == ' tmf') { // fmtチャンクならfmtを読み込み fmt = reinterpret_cast<Fmt*>(new char[chank.size]); if(fread(fmt, 1, chank.size, file) == 0) { delete [] fmt; fclose(file); exit(-1); } channel = fmt->channel; sampls_per_sec = fmt->sampls_per_sec; delete [] fmt; } else { // その他のチャンクならスキップ if(chank.size != 0) { if(fseek(file, chank.size, SEEK_CUR) != 0) { fclose(file); exit(-1); } } } } if(((channel < 1) && (channel > 2)) || (sampls_per_sec == 0)) { fclose(file); exit(-1); } // OpenAL初期化 ALCdevice* device_handle; ALCcontext* context_handle; ALuint source_handle; ALint state; device_handle = alcOpenDevice(NULL); context_handle = alcCreateContext(device_handle, NULL); alcMakeContextCurrent(context_handle); alGenSources(1, &source_handle); // waveをOpenALでストリーミング再生 for(;;) { ALint processed_count; ALint buffer_count; // 再生し終わったバッファがあれば削除する alGetSourcei(source_handle, AL_BUFFERS_PROCESSED, &processed_count); if(processed_count) { ALuint delete_buffer_handle[BUFFER_MAX]; alSourceUnqueueBuffers(source_handle, processed_count, delete_buffer_handle); } // ソースに登録可能ならバッファを作成して登録する alGetSourcei(source_handle, AL_BUFFERS_QUEUED, &buffer_count); if(buffer_count < BUFFER_MAX) { int16_t data[DATA_SAMPLE_MAX]; size_t readsize; // wave読み込み readsize = fread(data, 1, DATA_SAMPLE_MAX * 2, file); if(readsize != 0) { ALuint buffer_handle; // バッファ作成 alGenBuffers(1, &buffer_handle); alBufferData(buffer_handle, (channel == 1 ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16), data, static_cast<ALsizei>(readsize), sampls_per_sec); // ソースに登録 alSourceQueueBuffers(source_handle, 1, &buffer_handle); alDeleteBuffers(1, &buffer_handle); // 再生していない場合は再生する alGetSourcei(source_handle, AL_SOURCE_STATE, &state); if(state != AL_PLAYING) { alSourcePlay(source_handle); } } else { // データの終わりに到達したので再生が終了したら演奏終了 alGetSourcei(source_handle, AL_SOURCE_STATE, &state); if(state != AL_PLAYING) { break; } } } Sleep(100); } // 終了 fclose(file); alDeleteSources(1, &source_handle); alcMakeContextCurrent(NULL); alcDestroyContext(context_handle); alcCloseDevice(device_handle); return 0; }
wavファイルをopenalstream_sample.exeにドラッグアンドドロップしてください。
アプリケーション→ユーティリティに入っているターミナルを開く。 openalstreamの実行ファイルをドラッグアンドドロップでターミナルにドロップする。 次に再生したいwavファイルをターミナルにドロップする。 ターミナルでReturn(Enter)キーを押して実行する。
(Windows版)
(MacOSX版)
(Windows版)
(MacOSX版)
前に戻る?