第168章 Waveを記録し保存する


今回は、waveを記録して保存します。 特に難しくはありませんが、ちょっとした注意があります。

LONG MCIWndNew( hwnd, lp );

現在のデバイスのために新しいファイルを作成します。
lpにはMCIデバイスの名前を指定します。"waveaudio", "sequencer", "videodisc"などを指定します。

LONG MCIWndRecord( hwnd );

MCIデバイスに記録を開始させます。記録は現在位置から開始されます。

BOOL MCIWndCanRecord( hwnd );

記録できるかどうかを調べます。可能ならTRUE、不可能ならFALSEを返します。

LONG MCIWndSave( hwnd, szFile );

現在のコンテンツを保存します。
szFileにはパス付きのファイル名を指定します。

さて、次のようなプログラムを書くと思い通りに動作しません。

MCIWndNew(hMCIWnd, "waveaudio"); MCIWndRecord(hMCIWnd); MCIWndSave(hMCIWnd, FileName);

記録中にすぐにMCIWndRecordマクロは制御を戻してくるので 次のMCIWndSaveマクロが実行されてしまいます。

では、プログラムを見てみることにします。

// mciwnd03.rcの一部 ///////////////////////////////////////////////////////////////////////////// // // Menu // MYMENU MENU DISCARDABLE BEGIN POPUP "ファイル(&F)" BEGIN MENUITEM "開く(&O)", IDM_OPEN MENUITEM "閉じる(&C)", IDM_CLOSE MENUITEM SEPARATOR MENUITEM "終了(&X)", IDM_END END POPUP "MCI(&M)" BEGIN MENUITEM "プレイ(&P)", IDM_PLAY MENUITEM "ポーズ", IDM_PAUSE MENUITEM "リバース(&R)", IDM_REVERSE MENUITEM "最後に(&E)", IDM_POSEND MENUITEM "最初に(&S)", IDM_POSSTART MENUITEM "停止(&T)", IDM_STOP MENUITEM "EJECT", IDM_EJECT MENUITEM "wavの新規記録", IDM_RECORD MENUITEM "保存", IDM_SAVE END END

IDM_RECORD, IDM_SAVEが新たに増えました。

// mciwnd03.cpp #ifndef STRICT #define STRICT #endif #include <windows.h> #include <vfw.h> #include "resource.h" LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); ATOM InitApp(HINSTANCE); BOOL InitInstance(HINSTANCE, int); void OpenMyMci(HWND, char *, char *, int nFlag); BOOL CheckWindowSize(HWND, HWND); int AdjustSize(HWND, HWND); char szClassName[] = "mciwnd03"; //ウィンドウクラス HINSTANCE hInst;

OpenMyMci関数の引数を一つ増やしました。nFlagの値によって 開くと保存を使い分けるためです。

int WINAPI WinMain(HINSTANCE hCurInst, HINSTANCE hPrevInst, LPSTR lpsCmdLine, int nCmdShow) { MSG msg; hInst = hCurInst; if (!InitApp(hCurInst)) return FALSE; if (!InitInstance(hCurInst, nCmdShow)) return FALSE; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return msg.wParam; } //ウィンドウ・クラスの登録 ATOM InitApp(HINSTANCE hInst) { WNDCLASSEX wc; wc.cbSize = sizeof(WNDCLASSEX); wc.style = CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = WndProc; //プロシージャ名 wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInst; //インスタンス wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.lpszMenuName = "MYMENU"; //メニュー名 wc.lpszClassName = (LPCSTR)szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); return (RegisterClassEx(&wc)); } //ウィンドウの生成 BOOL InitInstance(HINSTANCE hInst, int nCmdShow) { HWND hWnd; hWnd = CreateWindow(szClassName, "猫でもわかるMCIWnd", //タイトルバーにこの名前が表示されます WS_OVERLAPPEDWINDOW, //ウィンドウの種類 CW_USEDEFAULT, //X座標 CW_USEDEFAULT, //Y座標 CW_USEDEFAULT, //幅 CW_USEDEFAULT, //高さ NULL, //親ウィンドウのハンドル、親を作るときはNULL NULL, //メニューハンドル、クラスメニューを使うときはNULL hInst, //インスタンスハンドル NULL); if (!hWnd) return FALSE; ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); return TRUE; }

これは、前回と全く同じです。

//ウィンドウプロシージャ LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) { int id; static HWND hMCIWnd; static char FileName[MAX_PATH]; static char szFTitle[64]; char szTitle[64]; static BOOL bRecord = FALSE; HMENU hMenu; switch (msg) { case WM_INITMENU: hMenu = GetMenu(hWnd); if (bRecord) { EnableMenuItem(hMenu, IDM_SAVE, MF_ENABLED | MF_BYCOMMAND); } else { EnableMenuItem(hMenu, IDM_SAVE, MF_GRAYED | MF_BYCOMMAND); } break; case WM_COMMAND: switch (LOWORD(wp)) { case IDM_END: SendMessage(hWnd, WM_CLOSE, 0, 0); break; case IDM_OPEN: OpenMyMci(hWnd, FileName, szFTitle, 0); MCIWndOpen(hMCIWnd, FileName, NULL); AdjustSize(hWnd, hMCIWnd); wsprintf(szTitle, "猫でもわかるMCI-%s-", szFTitle); SetWindowText(hWnd, szTitle); break; case IDM_PLAY: if (!MCIWndCanPlay(hMCIWnd)) { MessageBox(hWnd, "再生できません", "Error", MB_OK); break; } MCIWndPlay(hMCIWnd); break; case IDM_REVERSE: MCIWndPlayReverse(hMCIWnd); break; case IDM_PAUSE: MCIWndPause(hMCIWnd); break; case IDM_POSEND: MCIWndEnd(hMCIWnd); break; case IDM_POSSTART: MCIWndHome(hMCIWnd); break; case IDM_STOP: MCIWndStop(hMCIWnd); break; case IDM_CLOSE: MCIWndClose(hMCIWnd); AdjustSize(hWnd, hMCIWnd); strcpy(szTitle, ""); strcpy(FileName, ""); SetWindowText(hWnd, "猫でもわかるMCI"); break; case IDM_EJECT: if (!MCIWndCanEject(hMCIWnd)) { MessageBox(hWnd, "メディアを排出できません", "Error", MB_OK); } else { MCIWndEject(hMCIWnd); } break; case IDM_RECORD: OpenMyMci(hMCIWnd, FileName, szFTitle, 1); MCIWndNew(hMCIWnd, "waveaudio"); if (!MCIWndCanRecord(hMCIWnd)) { MessageBox(hWnd, "記録できません", "Error", MB_OK); break; } wsprintf(szTitle, "猫でもわかるMCI-%s-", szFTitle); SetWindowText(hWnd, szTitle); MCIWndRecord(hMCIWnd); bRecord = TRUE; break; case IDM_SAVE: if (strcmp(FileName, "") == 0) { MessageBox(hWnd, "記録できません", "Error", MB_OK); break; } MCIWndSave(hMCIWnd, FileName); break; } break; case WM_CREATE: hMCIWnd = MCIWndCreate(hWnd, hInst, 0, NULL); if (hMCIWnd == NULL) { MessageBox(hWnd, "MCIウィンドウ作成失敗", "Error", MB_OK); break; } MCIWndChangeStyles(hMCIWnd, MCIWNDF_NOOPEN, MCIWNDF_NOOPEN); AdjustSize(hWnd, hMCIWnd); break; case WM_SIZE: MoveWindow(hMCIWnd, 0, 0, LOWORD(lp), HIWORD(lp), TRUE); break; case WM_CLOSE: id = MessageBox(hWnd, "終了してもよいですか", "終了確認", MB_YESNO | MB_ICONQUESTION); if (id == IDYES) { MCIWndDestroy(hMCIWnd); DestroyWindow(hWnd); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return (DefWindowProc(hWnd, msg, wp, lp)); } return 0; }

WM_MENUINITが来るとbRecordの値を調べて、「保存」をグレー表示か 使用可能かを決めています。

IDM_RECORDが来たら、まずファイル名を決めてMCIWndNewでwaveaudioの 新しいファイルを作ります。そのあと、タイトルバーの表示を変えたり bRecordをTRUEにしたりしています。

IDM_SAVEが来たら保存しますが、これが実行される前にIDM_CLOSEが 実行されているかもしれません。それでFileNameに文字列が入っていない時は その旨注意を促すようにしました。

void OpenMyMci(HWND hWnd, char *szFileName, char *szFileTitle, int n) { OPENFILENAME ofn; static int nIndex = 0; static char szInitialDir[MAX_PATH] = ""; memset(&ofn, 0, sizeof(OPENFILENAME)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = hWnd; ofn.lpstrFile = szFileName; ofn.nMaxFile = 256; if (n == 0) { ofn.Flags = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; ofn.lpstrFilter = "MIDI(*.mid)\0*.mid\0waveaudio(*.wav)\0*.wav\0digitalvideo(*.avi)\0*.avi\0All Files(*.*)\0*.*\0\0"; } else { ofn.Flags = OFN_HIDEREADONLY; ofn.lpstrFilter = "waveaudio(*.wav)\0*.wav\0\0"; ofn.lpstrDefExt = "wav"; } ofn.lpstrTitle = "マルチメディア"; ofn.nFilterIndex = nIndex; ofn.lpstrInitialDir = szInitialDir; ofn.lpstrFileTitle = szFileTitle; ofn.nMaxFileTitle = 64; if (n == 0) GetOpenFileName(&ofn); else GetSaveFileName(&ofn); nIndex = ofn.nFilterIndex; strcpy(szInitialDir, ofn.lpstrInitialDir); return; }

最初にも書いたように、引数を増やしました。最後の引数が0 の時は「開く」で1の時は「保存」です。 「保存」の時はフィルタはwavのみです。またユーザーが拡張子を 入力しなくてもlpstrDefExtをwavに指定しているので自動的にwavが付きます。

int AdjustSize(HWND hWnd, HWND hMCIWnd) { RECT rc; int nMenuSize; GetWindowRect(hMCIWnd, &rc); if (MCIWndCanWindow(hMCIWnd) && rc.bottom - rc.top < 80) rc.bottom = rc.top + 80; AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, TRUE); MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, TRUE); nMenuSize = GetSystemMetrics(SM_CYMENU); if (!CheckWindowSize(hWnd, hMCIWnd)) { if(MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top + nMenuSize, TRUE) == 0) { MessageBox(hWnd, "MoveWindow失敗", "Error", MB_OK); return -1; } } return 0; } BOOL CheckWindowSize(HWND hWnd, HWND hMCIWnd) { RECT rc1, rc2; GetClientRect(hWnd, &rc1); GetWindowRect(hMCIWnd, &rc2); if (rc1.bottom - rc1.top == rc2.bottom - rc2.top) return TRUE; else return FALSE; }

これらの関数は前回と同じです。

さて、今回のプログラムではwaveの保存をできるようにしました。 waveを保存する時、拡張子なしのファイル名で保存するとどうなるでしょうか。 たとえば"test"と言う名前で保存します。次にこれを開きます。 再生は普通にできます。ところが、逆再生もできるようになります。 ("test.wav"の逆再生はできない)いろいろ実験してみると面白いことが わかります。


[SDK第2部 Index] [総合Index] [Previous Chapter] [Next Chapter]

Update 06/Jan/1999 By Y.Kumei
当ホーム・ページの一部または全部を無断で複写、複製、 転載あるいはコンピュータ等のファイルに保存することを禁じます。