開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 プロジェクト
プロジェクト名 TestMP3
アプリケーションの種類 Windows アプリケーション
追加のオプション 空のプロジェクト

参考

TestMP3.cpp
// TestMP3 MP3ファイルの再生
 
#pragma comment(lib, "winmm")
#pragma comment(lib, "msacm32")
 
#include <Windows.h>
#include <MMReg.h>
#include <MSAcm.h>
#include "resource.h"
 
struct ID3V2HEADER {
	BYTE id[3];
	BYTE version[2];
	BYTE flag;
	BYTE size[4];
};
typedef ID3V2HEADER *LPID3V2HEADER;
 
// 関数プロトタイプ宣言
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnDropFiles(HWND hDlg, WPARAM wParam);
void OnPlay(HWND hDlg);
void OnStop(HWND hDlg);
void Stop(void);
BOOL IsId3v2(LPBYTE lpData, DWORD dwDataSize, LPDWORD lpdwTagSize);
BOOL GetMp3Format(LPBYTE lpData, LPMPEGLAYER3WAVEFORMAT lpmf);
BOOL DecodeToWave(LPWAVEFORMATEX lpwfSrc, LPBYTE lpSrcData, DWORD dwSrcSize, LPWAVEFORMATEX lpwfDest, LPBYTE *lplpDestData, LPDWORD lpdwDestSize);
BOOL LoadMP3(LPTSTR lpszFile, LPMPEGLAYER3WAVEFORMAT lpmf, LPBYTE *lplpData, LPDWORD lpdwSize);
 
// 外部変数
TCHAR szFile[MAX_PATH];
LPBYTE lpWaveData;
HWAVEOUT hwo;
WAVEHDR wh;
 
//==============================================================================
int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE, LPSTR, int)
{
	DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG), NULL, DlgProc);
	return 0;
}
 
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	INT_PTR result = TRUE;
 
	switch (uMsg) {
	case MM_WOM_DONE:
		//waveOutWrite((HWAVEOUT)wParam, (LPWAVEHDR)lParam, sizeof(WAVEHDR));
		OnStop(hDlg);
		break;
	case WM_COMMAND:
		switch (LOWORD(wParam)) {
		case IDOK:
			OnPlay(hDlg);
			break;
		case IDCANCEL:
			OnStop(hDlg);
			break;
		}
		break;
	case WM_DROPFILES:
		OnDropFiles(hDlg, wParam);
		DragFinish((HDROP)wParam);
		break;
	case WM_CLOSE:
		EndDialog(hDlg, 0);
		break;
	case WM_DESTROY:
		Stop();
		break;
	default:
		result = FALSE;
	}
	return result;
}
 
void OnDropFiles(HWND hDlg, WPARAM wParam)
{
	HDROP hDrop = (HDROP)wParam;
	DragQueryFile(hDrop, 0, szFile, _countof(szFile));
	SetDlgItemText(hDlg, IDC_EDIT, szFile);
}
 
void OnPlay(HWND hDlg)
{
	DWORD dwMP3Size;
	LPBYTE lpMP3Data = NULL;
	MPEGLAYER3WAVEFORMAT mf;
	if (!LoadMP3(szFile, &mf, &lpMP3Data, &dwMP3Size)) {
		return;
	}
 
	WAVEFORMATEX wf;
	DWORD dwWaveSize;
	if (!DecodeToWave((LPWAVEFORMATEX)&mf, lpMP3Data, dwMP3Size, &wf, &lpWaveData, &dwWaveSize)) {
		delete[] lpMP3Data;
		return;
	}
	delete[] lpMP3Data;
 
	if (waveOutOpen(&hwo, WAVE_MAPPER, &wf, (DWORD_PTR)hDlg, 0, CALLBACK_WINDOW) != MMSYSERR_NOERROR) {
		return;
	}
	wh.lpData		= (LPSTR)lpWaveData;
	wh.dwBufferLength	= dwWaveSize;
	wh.dwFlags		= 0;
	waveOutPrepareHeader(hwo, &wh, sizeof(WAVEHDR));
	waveOutWrite(hwo, &wh, sizeof(WAVEHDR));
 
	EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
}
 
void OnStop(HWND hDlg)
{
	Stop();
	EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
}
 
void Stop(void)
{
	if (hwo) {
		waveOutReset(hwo);
		waveOutUnprepareHeader(hwo, &wh, sizeof(WAVEHDR));
		waveOutClose(hwo);
		hwo = NULL;
	}
	if (lpWaveData) {
		delete[] lpWaveData;
		lpWaveData = NULL;
	}
}
 
BOOL GetMp3Format(LPBYTE lpData, LPMPEGLAYER3WAVEFORMAT lpmf)
{
	static const DWORD dwBitTableLayer3[][16] = {
		{0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 0},
		{0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 0}
	};
	static const DWORD dwSampleTable[][3] = {
		{44100, 48000, 32000},
		{22050, 24000, 16000}
	};
 
	// 同期ヘッダ
	if (lpData[0] != 0xff || lpData[1] >> 5 != 0x07) {
		return FALSE;
	}
 
	// バージョン
	BYTE version;
	switch (lpData[1] >> 3 & 0x03) {
	case 3:	// 11=MPEG1
		version = 1;
		break;
	case 2:	// 10=MPEG2
		version = 2;
		break;
	default:
		return FALSE;
	}
 
	// レイヤー
	if ((lpData[1] >> 1 & 0x03) != 1) {	// 01=Leyer3
		return FALSE;
	}
 
	// ビットレート
	BYTE index = lpData[2] >> 4;
	DWORD dwBitRate = dwBitTableLayer3[version - 1][index];
 
	// サンプリングレート
	index = lpData[2] >> 2 & 0x03;
	DWORD dwSampleRate = dwSampleTable[version - 1][index];
 
	// パディング
	BYTE padding = lpData[2] >> 1 & 0x01;
 
	// チャンネルモード
	BYTE channel = (lpData[3] >> 6) == 3 ? 1 : 2;	// 11=シングルチャネル
 
	WORD wBlockSize = (WORD)((1152 * dwBitRate * 1000 / dwSampleRate) / 8) + padding;
 
	lpmf->wfx.wFormatTag		= WAVE_FORMAT_MPEGLAYER3;
	lpmf->wfx.nChannels		= channel;
	lpmf->wfx.nSamplesPerSec	= dwSampleRate;
	lpmf->wfx.nAvgBytesPerSec	= (dwBitRate * 1000) / 8;
	lpmf->wfx.nBlockAlign		= 1;
	lpmf->wfx.wBitsPerSample	= 0;
	lpmf->wfx.cbSize		= MPEGLAYER3_WFX_EXTRA_BYTES;
 
	lpmf->wID		= MPEGLAYER3_ID_MPEG;
	lpmf->fdwFlags		= padding ? MPEGLAYER3_FLAG_PADDING_ON : MPEGLAYER3_FLAG_PADDING_OFF;
	lpmf->nBlockSize	= wBlockSize;
	lpmf->nFramesPerBlock	= 1;
	lpmf->nCodecDelay	= 0x571;
 
	return TRUE;
}
 
BOOL DecodeToWave(LPWAVEFORMATEX lpwfSrc, LPBYTE lpSrcData, DWORD dwSrcSize, LPWAVEFORMATEX lpwfDest, LPBYTE *lplpDestData, LPDWORD lpdwDestSize)
{
	lpwfDest->wFormatTag = WAVE_FORMAT_PCM;
	acmFormatSuggest(NULL, lpwfSrc, lpwfDest, sizeof(WAVEFORMATEX), ACM_FORMATSUGGESTF_WFORMATTAG);
 
	HACMSTREAM has;
	if (acmStreamOpen(&has, NULL, lpwfSrc, lpwfDest, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME) != 0) {
		MessageBox(NULL, TEXT("変換ストリームのオープンに失敗しました。"), NULL, MB_ICONWARNING);
		return FALSE;
	}
 
	DWORD dwDestSize;
	acmStreamSize(has, dwSrcSize, &dwDestSize, ACM_STREAMSIZEF_SOURCE);
	LPBYTE lpDestData = new BYTE[dwDestSize];
 
	ACMSTREAMHEADER ash;
	ZeroMemory(&ash, sizeof(ACMSTREAMHEADER));
	ash.cbStruct	= sizeof(ACMSTREAMHEADER);
	ash.pbSrc	= lpSrcData;
	ash.cbSrcLength	= dwSrcSize;
	ash.pbDst	= lpDestData;
	ash.cbDstLength	= dwDestSize;
 
	acmStreamPrepareHeader(has, &ash, 0);
	BOOL bResult = (acmStreamConvert(has, &ash, 0) == 0);
	acmStreamUnprepareHeader(has, &ash, 0);
 
	if (bResult) {
		*lplpDestData = lpDestData;
		*lpdwDestSize = ash.cbDstLengthUsed;
	} else {
		MessageBox(NULL, TEXT("変換に失敗しました。"), NULL, MB_ICONWARNING);
		*lplpDestData = NULL;
		*lpdwDestSize = 0;
		delete[] lpDestData;
	}
	return bResult;
}
 
BOOL IsId3v2(LPBYTE lpData, DWORD dwDataSize, LPDWORD lpdwTagSize)
{
	BOOL bResult;
	LPID3V2HEADER lpHeader = (LPID3V2HEADER)lpData;
 
	if (memcmp(lpHeader->id, "ID3", 3) == 0) {
		*lpdwTagSize = ((lpHeader->size[0] << 21)|(lpHeader->size[1] << 14)|(lpHeader->size[2] << 7)|(lpHeader->size[3])) + 10;
		bResult = TRUE;
	} else {
		LPBYTE lp = (lpData + dwDataSize) - 128;
		*lpdwTagSize = (memcmp(lp, "TAG", 3) == 0) ? 128 : 0;
		bResult = FALSE;
	}
	return bResult;
}
 
BOOL LoadMP3(LPTSTR lpszFileName, LPMPEGLAYER3WAVEFORMAT lpmf, LPBYTE *lplpData, LPDWORD lpdwSize)
{
	HMMIO hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ);
	if (hmmio == NULL) {
		MessageBox(NULL, TEXT("ファイルのオープンに失敗しました。"), NULL, MB_ICONWARNING);
		return FALSE;
	}
 
	DWORD dwSize = mmioSeek(hmmio, 0, SEEK_END);
	LPBYTE lpData = new BYTE[dwSize];
	mmioSeek(hmmio, 0, SEEK_SET);
	mmioRead(hmmio, (HPSTR)lpData, dwSize);
	mmioClose(hmmio, 0);
 
	DWORD dwTagSize;
	LPBYTE lpMp3Data;
	if (IsId3v2(lpData, dwSize, &dwTagSize)) {
		dwSize -= dwTagSize;
		lpMp3Data = new BYTE[dwSize];
		CopyMemory(lpMp3Data, lpData + dwTagSize, dwSize);
		delete[] lpData;
	} else {
		dwSize -= dwTagSize;
		lpMp3Data = lpData;
	}
 
	if (!GetMp3Format(lpMp3Data, lpmf)) {
		delete[] lpMp3Data;
		return FALSE;
	}
 
	*lplpData = lpMp3Data;
	*lpdwSize = dwSize;
	return TRUE;
}
 

resource.h
#define IDD_DIALOG	100
 
#define IDC_EDIT	1000
//#define IDC_PLAY	1001
//#define IDC_STOP	1002
 

TestMP3.rc
// resource script
 
#include <Windows.h>
#include "resource.h"
 
IDD_DIALOG DIALOGEX 100, 100, 320, 200
STYLE WS_POPUPWINDOW | WS_MINIMIZEBOX
EXSTYLE WS_EX_APPWINDOW | WS_EX_ACCEPTFILES
CAPTION "TestMP3"
FONT 9, "MS Pゴシック"
BEGIN
	EDITTEXT	IDC_EDIT,10,10,300,150
	DEFPUSHBUTTON	"Play(&P)",IDOK,200,170,50,15
	PUSHBUTTON	"Stop(&S)",IDCANCEL,260,170,50,15
END
 
最終更新:2013年03月06日 09:58