// TestMP3_2 MP3ファイルの概要
#pragma comment(lib, "winmm")
#include <Windows.h>
#include <MMReg.h>
#include <stdio.h>
#include <string>
#include "resource.h"
using namespace std;
typedef struct {
BYTE id[3];
BYTE version[2];
BYTE flag;
BYTE size[4];
} ID3V2HEADER, *LPID3V2HEADER;
// 関数プロトタイプ宣言
INT_PTR CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
void OnDropFiles(HWND hDlg, WPARAM wParam);
void Trace(LPCTSTR format, ...);
BOOL LoadMP3(LPTSTR lpszFile);
BOOL GetMP3Format(LPBYTE lpData);
// 外部変数
wstring str;
//==============================================================================
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 WM_COMMAND:
switch (LOWORD(wParam)) {
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
}
break;
case WM_DROPFILES:
OnDropFiles(hDlg, wParam);
DragFinish((HDROP)wParam);
break;
case WM_CLOSE:
EndDialog(hDlg, 0);
break;
default:
result = FALSE;
}
return result;
}
void OnDropFiles(HWND hDlg, WPARAM wParam)
{
HDROP hDrop = (HDROP)wParam;
TCHAR szFile[MAX_PATH];
DragQueryFile(hDrop, 0, szFile, _countof(szFile));
TCHAR title[256];
swprintf_s(title, TEXT("%s - %s"), TEXT("TestMP3"), szFile);
SetWindowText(hDlg, title);
str.clear();
if (!LoadMP3(szFile)) {
return;
}
SetWindowText(GetDlgItem(hDlg, IDC_EDIT), str.c_str());
}
void Trace(LPCTSTR format, ...)
{
va_list arg_ptr;
va_start(arg_ptr, format);
TCHAR buffer[256];
int size = _vsnwprintf_s(buffer, _TRUNCATE, format, arg_ptr);
va_end(arg_ptr);
str += buffer;
str += TEXT("\r\n");
}
BOOL LoadMP3(LPTSTR lpszFileName)
{
// MP3ファイル部
HMMIO hmmio = mmioOpen(lpszFileName, NULL, MMIO_READ);
if (hmmio == NULL) {
MessageBox(NULL, TEXT("ファイルのオープンに失敗しました。"), NULL, MB_ICONWARNING);
return FALSE;
}
DWORD dwFile = mmioSeek(hmmio, 0, SEEK_END);
LPBYTE lpFile = new BYTE[dwFile];
mmioSeek(hmmio, 0, SEEK_SET);
mmioRead(hmmio, (HPSTR)lpFile, dwFile);
mmioClose(hmmio, 0);
// MP3データ部
DWORD dwData = dwFile;
LPBYTE lpData = lpFile;
// ID3v1
if (128 <= dwFile && memcmp(lpFile + dwFile - 128, "TAG", 3) == 0) {
dwData -= 128;
Trace(TEXT("ID3v1: o"));
} else {
Trace(TEXT("ID3v1: x"));
}
// ID3v2
if (10 <= dwData && memcmp(lpFile, "ID3", 3) == 0) {
LPID3V2HEADER lpHeader = (LPID3V2HEADER)lpFile;
LPBYTE size = lpHeader->size;
DWORD dwTagSize = ((size[0]<<21)|(size[1]<<14)|(size[2]<<7)|size[3]) + 10;
dwData -= dwTagSize;
lpData = lpFile + dwTagSize;
Trace(TEXT("ID3v2: o"));
Trace(TEXT("Version: %u"), lpHeader->version[0]);
Trace(TEXT("Size: %u %#x"), dwTagSize, dwTagSize);
} else {
Trace(TEXT("ID3v2:x"));
}
GetMP3Format(lpData);
delete[] lpFile;
return TRUE;
}
BOOL GetMP3Format(LPBYTE lpData)
{
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=シングルチャネル
Trace(TEXT("----"));
Trace(TEXT("Version: MPEG%u"), version);
Trace(TEXT("Layer: 3"));
Trace(TEXT("Bit Rate: %u kbps"), dwBitRate);
Trace(TEXT("Sampling Rate: %u Hz"), dwSampleRate);
Trace(TEXT("Channels: %u"), channel);
return TRUE;
}