EternalWindows
マルチメディア入力 / マルチメディアファイル入出力

Windows Multimediaに分類される関数群には、 マルチメディアファイルの再生に関わらないものも存在します。 そうした関数群の中でも比較的よく使用されるのは、マルチメディア入力だと思われます。 マルチメディア入力は、次に示す3つの関数群で構成されます。

マルチメディア入力の関数群 説明
マルチメディアファイル入出力 マルチメディアファイルからデータを取得したり書き込む場合に使用する。
ジョイスティック ジョイスティックやゲームパッドから入力を検出する場合に使用する。
マルチメディアタイマ 分解能の高い高精度な時間を取得したい場合に使用する。

今回から数回にわたって、マルチメディアファイル入出力について説明します。 こうした関数群を使わずに、CreateFileやWriteFileなどの関数を呼び出しても問題ありませんが、 マルチメディアファイルのアクセスに対しては、 マルチメディアファイル入出力関数の方が便利に感じるでしょう。 これらの関数は引数がそれほど複雑ではありませんし、 RIFF形式のファイル用に特化した関数も含まれています。 マルチメディアファイル入出力における最初の作業は、 mmioOpenを呼び出して目的のファイルをオープンすることです。

HMMIO mmioOpen(
  LPTSTR szFilename,       
  LPMMIOINFO lpmmioinfo,  
  DWORD dwOpenFlags       
);

szFilenameは、オープンしたいファイル名を指定します。 lpmmioinfoは、MMIOINFO構造体のアドレスを指定します。 buffered I/Oを行わない場合は、NULLを指定して問題ありません。 dwOpenFlagsは、ファイルに対してどのような捜査を行うかを表す定数を指定します。 戻り値がマルチメディアファイル入出力のハンドルとなります。

マルチメディアファイル入出力のハンドルを取得すれば、mmioReadでファイル内のデータを取得することができます。

LONG mmioRead(
  HMMIO hmmio,  
  HPSTR pch,    
  LONG cch      
);

hmmioは、マルチメディアファイル入出力のハンドルを指定します。 pchは、データを受け取るバッファを指定します。 cchは、pchのサイズを指定します。

ファイルハンドルが表す位置は、最初ファイルの先頭を表しており、 mmioReadによって進むことになります。 ただし、mmioSeekを呼び出せば現在の位置を変更することができます。

LONG mmioSeek(
  HMMIO hmmio,  
  LONG lOffset, 
  int iOrigin   
);

hmmioは、マルチメディアファイル入出力のハンドルを指定します。 lOffsetは、特定の位置からのオフセットを指定します。 iOriginは、特定の位置を表す定数を指定します。 SEEK_CURが現在の位置、SEEK_ENDがファイルの終端、 SEEK_SETがファイルの先頭となります。 戻り値は、新しいファイルの位置になります。

マルチメディアファイル入出力のハンドルが不要になったら、mmioCloseを呼び出します。

MMRESULT mmioClose(
  HMMIO hmmio, 
  UINT wFlags  
);

hmmioは、マルチメディアファイル入出力のハンドルを指定します。 wFlagsは、0を指定して問題ありません。

今回のプログラムは、マルチメディアファイル入出力関数を使用して、ファイル全体を読み取ります。 対象とするファイルは、マルチメディア関係のファイルでなくても構いません。

#include <windows.h>

#pragma comment (lib, "winmm.lib")

int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR lpszCmdLine, int nCmdShow)
{
	HMMIO  hmmio;
	LPBYTE lp;
	DWORD  dwFileSize;
	
	hmmio = mmioOpen(TEXT("sample.wav"), NULL, MMIO_READ);
	if (hmmio == NULL) {
		MessageBox(NULL, TEXT("ファイルのオープンに失敗しました。"), NULL, MB_ICONWARNING);
		return FALSE;
	}
	
	dwFileSize = mmioSeek(hmmio, 0, SEEK_END);
	lp = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, dwFileSize);
	mmioSeek(hmmio, 0, SEEK_SET);
	mmioRead(hmmio, (HPSTR)lp, dwFileSize);
	
	if (*(LPDWORD)lp == *(LPDWORD)"RIFF") {
		TCHAR szBuf[256];
		lp += 8;
		wsprintf(szBuf, TEXT("%c%c%c%c"), lp[0], lp[1], lp[2], lp[3]);
		MessageBox(NULL, TEXT("RIFF形式のファイルです。"), szBuf, MB_OK);
	}
	else
		MessageBox(NULL, TEXT("RIFF形式のファイルではありません。"), TEXT("OK"), MB_OK);

	mmioClose(hmmio, 0);

	return 0;
}

ファイルを読み取るため、mmioOpenにMMIO_READを指定しています。 ファイル全体を読み取る処理は次のようになっています。

dwFileSize = mmioSeek(hmmio, 0, SEEK_END);
lp = (LPBYTE)HeapAlloc(GetProcessHeap(), 0, dwFileSize);
mmioSeek(hmmio, 0, SEEK_SET);
mmioRead(hmmio, (HPSTR)lp, dwFileSize);

ファイル全体を読み取るためには、ファイル全体のサイズを取得しなければなりません。 mmioSeekにSEEK_ENDを指定した場合、ファイルの位置がファイルの終端となり、 その位置が戻り値として返るため、これをファイルサイズとすることができます。 必要なメモリを確保した後に再びmmioSeekを呼び出しているのは、 終端まで移動したファイル位置を先頭に戻すためです。 この場合、SEEK_SETを指定することになります。

データを取得した後は、ファイルの先頭4バイトはRIFFという文字列であるかどうかを確認しています。 これは次節以降の内容を考慮しての事ですが、たとえばWAVEファイルを指定した場合は、 先頭の8バイト目から4バイトがWAVEという文字列になっています。 一方、AVIファイルを指定した場合は、AVIという文字列になっています。 これらのファイルはRIFF形式のファイルであり、 マルチメディア入出力関数を使えば目的のデータを簡単に取得することができるようになります。 詳しくは次節で取り上げます。


戻る