API

midi 파일 프로그래밍 참조

디버그정 2010. 4. 9. 12:25
///////////////////////////////////////////
winapi.co.kr 질답글 중~~~
MDI는 아니고 MCI 입니다.

API정복 책이 있다면. 그 책에도 간단히 나와 있긴 합니다.

물론 개정판의 경우는 VOLUME 2 에 있습니다.

MCI.. 사실 당장 필요한 함수는 두개 뿐입니다.

그것도 명령 메시지 방식에 하나...
명령 문자열 방식에 하나..

즉 둘중에 한개만 쓰면 됩니다.

명령 메시지 방식의 경우는 mciSendCommand..
명령 문자열 방식의 경우는 mciSendString...

명령 메시지 방식의 경우는..
윈도우 프로시저 방식과 똑같습니다...
메시지 상수값으로 구분하고..
나머지 몇몇 인자들에.. 여러 데이터를 구겨넣든지.. 포인터 타입을 캐스팅 하든지..
해서 넘겨주는 방식입니다.
물론 전부 다 구조체를 넘겨야 합니다.
Open 명령, Close명령, Seek명령, Pause 명령 Play ,명령..
전부 각 명령을 위한 구조체가 준비되어 있습니다.
MCI_OPEN_PARMS 구조체, MCI_SEEK_PARMS ... 등등..


명령 문자열 방식의 경우는 mciSendString 함수인데..
문자열에 모든 정보를 다 담아서 넘겨줍니다. 물론 문법 형식에 맞춰서 담아줘야 하죠...

이처럼.. 실질적인 작업은.. 메시지나.. 문자열에 담아서 보내기 때문에..
사실 필요한 함수가 많지도 않습니다.
OPEN, SEEK, CLOSE, PAUSE.. 전부 위 두 함수들로 처리합니다.
물론 둘중에 한개만 쓰면 됩니다.



참고로 MCI는.. 재생 뿐 아니라.. 녹음도 됩니다.
사운드 뿐만 아니라 동영상 재생도 지원하지요..
CDROM 드라이브도 이놈으로 제어할 수 있습니다.




여기 MCI에 대한 간단한 강좌가 있네요..
http://cafe.naver.com/gamemaker.cafe?iframe_url=/ArticleRead.nhn%3Farticleid=29

근데.. 여기는 MIDI 재생만 나와있긴 하네요
MCI로.. WAVE, MP3, MIDI, WMA 등.. 등 다 재생 가능하거든요..

하지만 다른 형식 재생도 어렵지 않습니다.
Open 함수에 보면...
mciOpenParms.lpstrDeviceType="sequencer";
mciOpenParms.lpstrElementName=szName;

여기서 lpstrDeviceTyhpe 이 "sequencer" 면 MIDI 재생이고..
lpstrDeviceType 이 "waveaudio" 면 WAVE 재생이고..
lpstrDeviceType 이 "mpegvideo" 면 MP3 재생이 됩니다.


한군데 더 찾았네요.
http://blog.naver.com/youtoo2?Redirect=Log&logNo=20014694780
여기입니다.
여기는 웨이브 재생만 나와있군요.
하지만.. 제가 위에서 언급해 드린 대로.. 하시면 다른 형식의 파일도 재생 가능하십니다.

여기는 sndPlaySound 함수도 나왔네요..
참고로 sndPlaySound 는.. 16비트 함수이기 때문에 현재 PlaySound로 대체되었습니다.
물론 지금 쓸수는 있지만..
그나저나 sndPlaySound 함수와 PlaySound 두 함수는

서로 동시에 재생이 될련지 의문이 생기는군요..
//////////////////////////////////////////////////////////////////////







게임 제작 강좌-프로그래밍 강좌 (go NGM)』 600번 제 목:[강좌] 심심강좌 25:MCI MIDI 올린이:myevan (송영진 ) 99/03/20 23:15 읽음:670 관련자료 없음 ----------------------------------------------------------------------------- 나우누리 게임 제작 포럼 심심강좌 미디연주 ... 엘리시아 이브 ====================================================================== 안녕하세요. 엘리시아 이브입니다. 요즘에 Direct Music 을 사용하면, 좋은 음질의 미디를 연주할 수 있다고 하더군요^^; 그런데... 아직 DirectX SDK 6.1 을 못 받아봐서요^^;; 먼저, MCI 를 이용한 미디 연주를 다루어 보도록 하겠습니다. MCI 를 이용한 음악 연주 방법에는 두가지 방법이 있습니다. 하나는 글줄을 통한 방법이고요, 다른 방법은 그냥 명령방식입니다. 예를 들면 "xxx.mid 를 연주해라!" -> 글줄 방식 "Func(xxx)" -> 그냥 명령방식 ( 함수로 실행 ) 이런 식으로 하는것을 말합니다. ( 요즘따라 왠지 x 라는 문자가 좋아지는군요^^; ) 에, 솔직히 두개의 차이는 잘 모르겠습니다^^; 비스므리 한것 같은데요. 암튼 후자 방식이 좀더 강좌로 하기 폼나면서,제 가 가지고 있는 자료가 후자이기 때문에 이번 강좌는 후자의 방법을 사용하 겠습니다. 글줄 방식은 CDX 라이브러리를 보시면 자세하게 나와있습니다. 1. 클래스 만들기 아무리 음악에 대한 감각이 0 점 이라고 해도. 기본적인 연주 방법은 이미 알고 계실듯합니다. 모르신다고요^^? -.-++ 자, 각설하고... 그럼 그냥 보도록 합시다. 어떤 데이터 자료를 처리하던지, 먼저 파일을 열고 봐야 합니다. 그럼 닫 는 함수가 있는건 당근이겠죠? 다음은 무엇인지 내용을 봐야하니까요, 그림 이라면 보여주기이고, 음악이라면... 연주겠죠? 연주를 한다면, 역시 중지 하는 것도 있어야 합니다. 또, 필요한 것들을 생각을 해보도록 합시다.연주 위치를 옮기는 것이 있으면 좋겠죠? 현재 위치를 얻는 것도 필요할테고요. 어느정도 머리를 굴려본듯 합니다. 자, 정리를 해볼까요? 열기 닫기 연주 연주중지 위치이동 위치얻기 자, 대략 이정도의 함수를 만드시면 됩니다. [MciMIDI.H] #ifndef __ETERNITY_MIDI__ #define __ETERNITY_MIDI__ #define WIN32_LEAN_AND_MEAN #include <windows.h> #include <mmsystem.h> class CMIDI { DWORD dwID; public: CMIDI(); int Open(char *szName); void Close(); int Play(HWND hWnd); void Stop(); void MoveStartPos(); void MoveEndPos(); DWORD GetPos(); void SetPos(DWORD Pos); }; #endif 위의 내용이 우리가 만들 미디 연주기의 헤더입니다. #define WIN32_LEAN_AND_MEAN 이건 API 방식으로 프로그래밍을 할때, 속도를 늘려주는 구문입니다. 의미만 알고 구체적인 내용은 모르겠습니다 T.T #include <windows.h> 윈도우 프로그램이니 당연 windows.h 가 포함되어야 겠죠? #include <mmsystem.h> MCI 장치는 멀티미디어 장치로 분류되기 때문에 mmsystem.h 에 존재합니다. DWORD dwID; 에... 미디 연주에 있어서 아이디라는게 필요합니다. CMIDI(); 생성자이죠? int Open(char *szName); void Close(); int Play(HWND hWnd); void Stop(); void SetPos(DWORD Pos); DWORD GetPos(); 아까 머리속으로 생각을 해본 필요한 함수들입니다. void MoveStartPos(); void MoveEndPos(); SetPos에 포함될 수 있는 함수이죠? 그런데... 작동방식이 약간 달라서.. 따로 만들어 두었습니다. **왜 파일이름은 MCIMIDI 인데... 클래스는 CMIDI 냐고요? ^^ 그냥 제 맘입니다. -_-; 맘에 안드시면 바꾸세요. 2. 만들기!! 자, 이제 실제 소스를 보도록 합시다. 같이 설명을 붙이도록 하겠습니다 [MCIMIDI.H] #include "MciMidi.H" CMIDI::CMIDI() { dwID=0xffff; } 언제나 생성자에서는 데이터 초기화를 해줍니다. 0이란 값은 존재할 가능성이 있지 않을까 해서... 파일이 읽혀지지 않은 상 태로 0xffff 를 정했습니다. ( 좀더 긴걸로 할껄 그랬나요. 만약 문제가 생 기시면 0xffffffff 으로 하세요^^;; 간단히 (DOWRD)-1 로 하셔도 될듯...) int CMIDI::Open(char *szName) { MCI_OPEN_PARMS mciOpenParms; mciOpenParms.lpstrDeviceType="sequencer"; mciOpenParms.lpstrElementName=szName; if(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT, (DWORD)&mciOpenParms)) { dwID=0xffff; return 0; } dwID=mciOpenParms.wDeviceID; return 1; } MCI_OPEN_PARMS mciOpenParms; mciOpenParms.lpstrDeviceType="sequencer"; MCI 장치 이름을 정합니다. 미디의 경우 midi 가 아니라 sequencer 임에 주 의하세요^^ mciOpenParms.lpstrElementName=szName; 여기에 파일이름을 등록시킵니다. if(mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT, (DWORD)&mciOpenParms)) { dwID=0xffff; return 0; } 파일을 연다는 명령을 보냅니다. 파일을 열수 없으면... 에러처리해야겠죠? dwID=mciOpenParms.wDeviceID; 파일을 열고난 후에 받아온 아이디를 등록시켜줍니다. void CMIDI::Close() { if(dwID==0xffff) return; MCI_GENERIC_PARMS mciGenericParms; mciSendCommand(dwID,MCI_PAUSE,MCI_WAIT,(DWORD)&mciGenericParms); dwID=0xffff; } if(dwID==0xffff) return; 미디가 그냥 열려진 상태에서 닫는 명령을 내리면(또는 다른 명령을 내리면 ) 윈도우에 흉한 일이 생깁니다^^; 사전에 방지를 해주세요! MCI_GENERIC_PARMS mciGenericParms; mciSendCommand(dwID,MCI_PAUSE,MCI_WAIT,(DWORD)&mciGenericParms); MCI 장치를 닫는 일을 합니다. dwID=0xffff; 당연히 파일을 닫는 후에는 아이디에 '열린거 없어'하는 아이디를 넣어주셔 야 겠죠? 흠.. 강좌를 쓰면서 생각해보니 0xffff 를 정의어로 해둘것을 잘 못 했군요. 여러분은 정의어로 두세요^^; int CMIDI::Play(HWND hWnd) { if(dwID==0xffff) return 0; MCI_PLAY_PARMS mciPlayParms; mciPlayParms.dwCallback=(DWORD)hWnd; if(mciSendCommand(dwID,MCI_PLAY,MCI_NOTIFY,(DWORD)&mciPlayParms)) return 0; return 1; } if(dwID==0xffff) return 0; 이 줄에 대해서는 앞에서 설명을 드렸었죠? MCI_PLAY_PARMS mciPlayParms; mciPlayParms.dwCallback=(DWORD)hWnd; if(mciSendCommand(dwID,MCI_PLAY,MCI_NOTIFY,(DWORD)&mciPlayParms)) return 0; MCI 장치 연주를 하는 것입니다. MCI_NOTIFY 라는 것이 보이시죠? 이건 MCI 장치가 중단되거나 혹은 정지되 었을때 MM_MCINOFIFY 라는 메시지가 발생되도록 하는 것입니다. 흠... 나머지 부분들은 굳이 주석이 필요없는 부분들이군요^^; 주석 생략합니다. DWORD CMIDI::GetPos() { if(dwID==0xffff) return 0xffff; MCI_STATUS_PARMS mciStatusParms; mciStatusParms.dwItem=MCI_STATUS_POSITION; mciSendCommand(dwID,MCI_STATUS,MCI_STATUS_ITEM,(DWORD)&mciStatusParms); return mciStatusParms.dwReturn; } void CMIDI::SetPos(DWORD Pos) { if(dwID==0xffff) return; MCI_SEEK_PARMS mciSeekParms; mciSeekParms.dwTo=Pos; mciSendCommand(dwID,MCI_SEEK,MCI_TO,(DWORD)&mciSeekParms); } void CMIDI::MoveStartPos() { if(dwID==0xffff) return; MCI_SEEK_PARMS mciSeekParms; mciSendCommand(dwID,MCI_SEEK,MCI_SEEK_TO_START,(DWORD)&mciSeekParms); } void CMIDI::MoveEndPos() { if(dwID==0xffff) return; MCI_SEEK_PARMS mciSeekParms; mciSendCommand(dwID,MCI_SEEK,MCI_SEEK_TO_END,(DWORD)&mciSeekParms); } void CMIDI::Stop() { if(dwID==0xffff) return; MCI_GENERIC_PARMS mciGenericParms; mciSendCommand(dwID,MCI_STOP,MCI_WAIT,(DWORD)&mciGenericParms); } 3. 연주! 연주 방법은 상당히 간단합니다. [연주시작시] CMIDI *CMidi=new CMIDI; CMidi->Open("파일이름.Mid"); CMidi->Play(윈도우핸들); [연주종료시] CMidi->Stop(); CMidi->Close(); delete CMidi; [MM_MCINOFITY 메시지 발생시] 단일 연주라면; 쌩하세요~^^; 반복 연주라면... CMidi->MoveStartPos(); CMidi->Play(윈도우핸들); 간단하죠^^? 빠른 시일내에 DMusic, DPlay 를 공부해서 강좌 올리도록 하겠습니다. ** 흠... 얼마전에 제작한 판어슈플를 강좌로 하고 싶은데, 어떻게 올려야 할지 모르겠내요^^ 실행되는 소스별로 나누어서 올리는게 가장 좋겠지만, 소스를 다시 만들어야 하니 너무 어렵고요^^; 그렇다고 실행 안되는 예제를 강좌로 쓰기도 그렇내요^^; ** 강좌 신청받습니다! ^^ ... myevan 이터니티 홈페이지 http://mypage.channeli.net/blaze79/eterpage.htm 제가 있는 팀의 홈페이지 입니다^^