관리 메뉴

ㄴrㅎnㅂrㄹrㄱi

[강좌 14] 멀티미디어2 본문

API 관련/API 강좌모음

[강좌 14] 멀티미디어2

님투 2007. 10. 26. 03:41
반응형

[API]강좌(14)<--멀티미디어2



자 그러면 여는 방법을 알았으니 닫는 방법도 알아 봅시다. 닫을때에는 close라는
문자열을 사용하면 됩니다. close 다음에는 닫을 장치의 아이디를 나타내는 문자
열을 지정해 주면 됩니다.
플레이할때에는 어떤 문자열을 사용할까요? 짐작이 가죠? 바로 play라는 문자열을
사용합니다. 역시 play 다음에 장치 아이디를 의미하는 문자열이 오고 그 다음에
notify라는 문자열이 옵니다. 이 문자열은 어디서 많이 보지 않았습니까? 잘
기억이 나지 않으면 앞 부분을 보세요. 아마 MCI_NOTIFY가 보일겁니다. 물론 그
역할도 같습니다. 플레이가 끝났을때 윈도우에 MM_MCINOTIFY 메시지를 보냅니다.
플레이를 중지할때에는 stop이라는 문자열을 사용하고 잠시 중단할때에는 pause
다시 플레이할때에는 resume이라는 문자열을 사용합니다. 물론 장치 아이디를
의미하는 문자열과 같이 쓰입니다.
그러면 실제로 문자열을 이용해서 플레이하는 프로그램을 작성해 봅시다.
아래는 리소스 파일입니다.
#include <windows.h>
MyMenu MENU
BEGIN
POPUP "&Wave"
BEGIN
MENUITEM "&Play", 100
MENUITEM "P&ause", 200
MENUITEM "&Resume", 300
MENUITEM "&Stop", 400
END
END
아래는 프로그램 파일입니다.
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <mmsystem.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char* Open(HWND hWnd);
void Play(HWND hWnd, char *str);
void Stop(HWND hWnd, char *str);
void Pause(HWND hWnd, char *str);
void Resume(HWND hWnd, char *str);
void Close(HWND hWnd, char *str);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
static char szAppName[] = "Multimedia Example";
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW|CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = "MyMenu";
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass))
return FALSE;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static char szID[80];
switch(message)
{
case WM_CREATE :
strcpy(szID, Open(hWnd));
return 0;
case MM_MCINOTIFY :
Close(hWnd, szID);
strcpy(szID, Open(hWnd));
return 0;
case WM_COMMAND :
switch(LOWORD(wParam))
{
case 100 :
Play(hWnd, szID);
break;
case 200 :
Pause(hWnd, szID);
break;
case 300 :
Resume(hWnd, szID);
break;
case 400 :
Stop(hWnd, szID);
break;
}
return 0;
case WM_DESTROY :
Close(hWnd, szID);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
char* Open(HWND hWnd)
{
MCIERROR mciError;
static char szReturn[80];
mciError = mciSendString("open d:\\test.wav type waveaudio alias wavefile",
szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Open Error!!", "Error", MB_OK);
return "wavefile";
}
void Play(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "play %s notify", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Play Error!!", "Error", MB_OK);
}
void Stop(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "stop %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Stop Error!!", "Error", MB_OK);
}
void Pause(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "pause %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Pause Error!!", "Error", MB_OK);
}
void Resume(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "resume %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Resume Error!!", "Error", MB_OK);
}
void Close(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "close %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Resume Error!!", "Error", MB_OK);
}
 
 
확장자가 mid인 미디 파일을 어떻게 플레이하는지 알아 보겠습니다.
아마 머리가 좋으신분은 이미 어떻게 구현하는지 짐작을 하고 있을 겁니다.
이곳도 역시 mciSendCommand()함수와 mciSendString()함수 두가지 방법을 이용해
서 구현할수 있습니다. 먼저 저번시간에 알아본 mciSendString()함수를 이용해
서 구현하는 방법을 알아 봅시다.
아주 간단합니다. 위에서 사용했던 MCI 장치 이름인 waveaudio 대신에 sequencer
를 사용하면 되는것입니다. 이 sequencer를 어디서 본것 같죠? 멀티미디어 처음
부분에서 system.ini 파일을 설명드렸을때 언급했을 겁니다. 이 문자열이 바로
미디 장치를 의미하는 것입니다. 자 그러면 이것을 이용해서 프로그램을 만들어
봅시다.

#include <windows.h>
MyMenu MENU
BEGIN
POPUP "&Midi"
BEGIN
MENUITEM "&Play", 100
MENUITEM "&Stop", 200
END
END
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <mmsystem.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
char* Open(HWND hWnd);
void Play(HWND hWnd, char *str);
void Stop(HWND hWnd, char *str);
void Close(HWND hWnd, char *str);
int WINAPI WinMain
(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszArg, int nCmdShow)
{
static char szAppName[] = "Multimedia Example";
HWND hWnd;
MSG msg;
WNDCLASS WndClass;
WndClass.style = CS_HREDRAW|CS_VREDRAW;
WndClass.lpfnWndProc = WndProc;
WndClass.cbClsExtra = 0;
WndClass.cbWndExtra = 0;
WndClass.hInstance = hInstance;
WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
WndClass.hbrBackground = GetStockObject(WHITE_BRUSH);
WndClass.lpszMenuName = "MyMenu";
WndClass.lpszClassName = szAppName;
if(!RegisterClass(&WndClass))
return FALSE;
hWnd = CreateWindow(
szAppName,
szAppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
NULL
);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK
WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static char szID[80];
switch(message)
{
case WM_CREATE :
strcpy(szID, Open(hWnd));
return 0;
case MM_MCINOTIFY :
Close(hWnd, szID);
strcpy(szID, Open(hWnd));
return 0;
case WM_COMMAND :
switch(LOWORD(wParam))
{
case 100 :
Play(hWnd, szID);
break;
case 200 :
Stop(hWnd, szID);
break;
}
return 0;
case WM_DESTROY :
Close(hWnd, szID);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
char* Open(HWND hWnd)
{
MCIERROR mciError;
static char szReturn[80];
mciError = mciSendString("open d:\\test.mid type sequencer alias midifile",
szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Open Error!!", "Error", MB_OK);
return "midifile";
}
void Play(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "play %s notify", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Play Error!!", "Error", MB_OK);
}
void Stop(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "stop %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Stop Error!!", "Error", MB_OK);
}
void Close(HWND hWnd, char *str)
{
MCIERROR mciError;
static char szReturn[80], szString[80];
sprintf(szString, "close %s", str);
mciError = mciSendString(szString, szReturn, 80, hWnd);
if(mciError)
MessageBox(hWnd, "Resume Error!!", "Error", MB_OK);
}


전체적으로 웨이브 파일을 플레이할때와 크게 달라진점은 없을 겁니다. 그런데 한
가지 이상한 점이 있죠? 바로 잠시중단하는 경우와 다시 플레이하는 기능이 위 프
로그램에서 빠져 있습니다. 왜 그럴까요? 우리는 파일을 플레이했을때 잠시 중단
하는 명령어인 pause라는 것을 사용했을 겁니다. 그런데 문제는 이 미디 파일을
플레이할때 pause문자열을 사용해서 잠시 중단하면 바로 MM_MCINOTIFY 메시지가
발생되는 것입니다. 이 메시지는 stop문자열을 사용해서 정지를 하거나 플레이가
끝났을깨 발생되는 메시지인데 pause 문자려에 의해서 이 메시지가 발생되는
resume 메시지 처리가 정상적으로 되지 않는다는 것입니다. 그렇기 때문에 이
기능을 위 프로그램에서 뺀것입니다. 대신 이 기능을 추가한것을 mciSendCommand()
함수를 이용해서 만들어 볼것입니다.
자 그러면 또 달라진 점을 보도록 하죠.
case MM_MCINOTIFY :
Close(hWnd, szID);
strcpy(szID, Open(hWnd));
return 0;
바로 위 메시지 처리 부분입니다. 웨이브 파일을 플레이했을때 발생되는
MM_MCINOTIFY 메시지 처리 부분과 다르죠? 장치를 닫아주고 다시 열어 주어야
다시 플레이를 선택했을때 바로 플레이가 가능해집니다.
이제 MCI 장치를 여는 Open()함수를 보도록 합시다.
char* Open(HWND hWnd)
{
MCIERROR mciError;
static char szReturn[80];
mciError = mciSendString("open d:\\test.mid type sequencer alias midifile",
szReturn, 80, hWnd);
함수의사용방법은 같습니다. 단 waveaudio라는 장치 이름대신에 미디 파일을 의미
하는 sequencer를 사용했습니다.
if(mciError)
MessageBox(hWnd, "Open Error!!", "Error", MB_OK);
에러 처리부분은 변한게 없구요.
return "midifile";
}
그 외에는 다른점이 없죠?
자 그러면 이번에는 PAUSE기능과 RESUME기능이 있는 미디 플레이를 구현해 봅시다.
이것을 구현할때 우리는 미디 파일을 플레이해주는 mciSendCommand()함수를 이용해
서 구현할것입니다. 이 함수의 사용방법을 다시 한번 상기 해 보십시요. 생각 납
니까? 잘 나지 않으면 조금 앞 부분을 다시 보기 바랍니다. 다시 설명 드리지 않
을테니까요.
전체적인 원리는 간단합니다. MCI_STOP을 사용해서 정지를 시키던 MCI_PAUSE를 이
용해서 정지를 시키던지 MM_MCINOTIFY메시지가 발생되니 어느 것에 의해서 이 메
시지가 발생되었는지 구분시켜 주어야 합니다. 그래야 각각 처리를 할테니까요.
이 문제는 변수 하나로 간단하게 해결할수 있습니다. 그래서 만약에 MCI_STOP에
의해서 정지가 된거면 우리가 웨이브 파일을 mciSendCommand()함수로 구현할때와
마찬가지로 플레이될 위치를 처음으로 옮겨주면 되고 그렇지 않고 MCI_PAUSE에
의해서 발생되었다면 현재 플레이된 위치를 얻어서 그 위치로 다시 세팅해주면
됩니다. 그리고 만약에 사용자가 resume을 선택한다면 MCI_RESUME을 이용해서 다시
플레이하는것이 아니라 MCI_PLAY를 이용해서 플레이 해주면 되는 것입니다.
플레이될 위치를 처음으로 옮기는 방법은 앞에서 알아 보았으니 생략하고 현재
플레이되고 있는 위치와 또 세팅하는 방법을 알아 보도록 합시다.
우리는 앞에서 mciSendCommand()함수를 사용할때 마지막 파라미터에 특수한 구조체
변수의 주소를 지정해 주었는데 현재 플레이된 곳의 위치를 얻고자 할때에도 특수
한 구조체 변수의 주소를 지정해 주어야 합니다. 이때 사용하는 구조체가 바로
MCI_STATUS_PARMS입니다.
typedef struct {
DWORD dwCallback;
DWORD dwReturn;
DWORD dwItem;
DWORD dwTrack;
} MCI_STATUS_PARMS;
멤버중 dwItem에 MCI_STATUS_POSITION이라는 예약어를 지정해준 다음에
mciSendCommand() 함수를 사용하면 됩니다.
mciStatusParms.dwItem = MCI_STATUS_POSITION;
mciError = mciSendCommand(dwID, MCI_STATUS, MCI_STATUS_ITEM,
(DWORD)&mciStatusParms);
바로 위와 같이 사용하면 됩니다. 두번째 파라미터에 MCI_STATUS를 지정하고 세번
째 파라미터에 MCI_STATUS_ITEM을 지정하면 됩니다.
위와 같이 사용하면 구조체 멤버중 dwReturn에 그 위치가 저장되니 이 값을 얻으면
바로 그 값이 위치가 되는 것입니다.
반응형

'API 관련 > API 강좌모음' 카테고리의 다른 글

[강좌 16] 멀티미디어4  (0) 2007.10.26
[강좌 15] 멀티미디어3  (0) 2007.10.26
[강좌 13] 멀티미디어1  (0) 2007.10.26
[강좌 12] 그래픽3  (0) 2007.10.26
[강좌 11] 그래픽2  (0) 2007.10.26
Comments