*第19回目 OpenALでストリーム再生 [#q39c64b5]
 OpenALでwavファイルのストリーム再生をしてみた。
 前回作成したリングバッファクラスやストリームクラスを使用していません。
 今回はOpenALで作ったサンプルプログラムです。
 手抜き実装のためwavファイルのフォーマットが8ビットの場合は再生できません。
**動作環境 [#e8ce4f71]
 Windows版はVisualStudio.NET2003用のWin32コンソールプロジェクト。
 WindowsXP SP2で動作確認。
 MacOSX版はXcode3.0のCommandLineUtilityのC++Toolプロジェクト。
 IntelOSX10.5.5で動作確認。PowerPCには対応したつもりなんだけど動作未確認。
#author("2018-06-18T16:05:07+09:00","default:kuran","kuran")

**サンプルプログラム (Windows版) [#ldd8f0da]
 #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);
 			alDeleteBuffers(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);
 				// 再生していない場合は再生する
 				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;
 }

**操作方法 [#o16de76c]
***windows [#sa60be8d]
 wavファイルをopenalstream_sample.exeにドラッグアンドドロップしてください。
***MacOSX [#ea91e7be]
 アプリケーション→ユーティリティに入っているターミナルを開く。
 openalstreamの実行ファイルをドラッグアンドドロップでターミナルにドロップする。
 次に再生したいwavファイルをターミナルにドロップする。
 ターミナルでReturn(Enter)キーを押して実行する。
**ダウンロード [#g1d85df4]
***実行ファイル [#q0779f83]
(Windows版)
#ref(http://www.ripple.gr.jp/~kuran_kuran/bin/download/openalstream_sample_windows_20091113.zip)~
(MacOSX版)
#ref(http://www.ripple.gr.jp/~kuran_kuran/bin/download/openalstream_sample_osx_20091113.zip)~
***ソースファイル [#na90fb3b]
(Windows版)
#ref(http://www.ripple.gr.jp/~kuran_kuran/bin/download/openalstream_sample_windows_source_20091113.zip)~
(MacOSX版)
#ref(http://www.ripple.gr.jp/~kuran_kuran/bin/download/openalstream_sample_osx_source_20091113.zip)~

[[前に戻る>プログラミング]]


トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS