c언어 콘솔에서 음악 동시에 재생하기(mcisendCommand, playsound)

목차

 

1.PlaySound()

 

#include <windows.h>
#pragma comment (lib, "winmm.lib")
#include <mmsystem.h>;

PlaySound(TEXT(wav파일의 위치), NULL, 옵션1 | 옵션2)

 

가장 간단한 방법은 PlaySound 함수를 이용하는 것이다.

이 함수를 이용하기 위해선 mmsystem.h 가 필요하다.

그리고 별도의 라이브러리로 winmm.lib가 필요하다. #pragma로 추가해주면 된다.

 

PlaySound(TEXT("bgm.wav"), NULL, SND_ASYNC)    // 일반 재생
PlaySound(TEXT("bgm.wav"), NULL, SND_ASYNC | SND_LOOP)    // 반복 재생

docs.microsoft.com/en-us/previous-versions/dd743680(v=vs.85)

 

PlaySound function (Windows)

PlaySound function 06/06/2016 4 minutes to read In this article --> The PlaySound function plays a sound specified by the given file name, resource, or system event. (A system event may be associated with a sound in the registry or in the WIN.INI file.) Sy

docs.microsoft.com

함수에 주어지는 인자를 자세히 알고 싶다면 microsoft에서 제공하는 정보를 참고하자.

하지만 이 함수는 내가 원하던 함수는 아니다.

우선 BGM을 깔아둔 채로 효과음을 재생할 수 없다.

또한 wav 파일을 사용하기 때문에 음악 파일의 용량이 크다.

단순히 BGM만 들리게 프로그램을 만든다면 간단하게 사용해볼 수 있겠지만, 부족한 점이 많다.

동시에 음악을 구현하려면 mciSendCommand 를 이용하면 된다.

 

 

2.MCI

 

MCI는 Media Control Interface의 약자로, mp3 파일도 재생할 수 있어서 이용하기 편하다.

docs.microsoft.com/ko-kr/windows/win32/multimedia/mci

 

MCI - Win32 apps

MCI

docs.microsoft.com

 

역시 마이크로소프트에서 문서를 제공하므로 자세한 정보를 알고 싶다면 접속해보시면 되겠다.

여기서는 '음악 동시 재생'을 위한 코드만 소개한다.

 

#include <windows.h>    //키보드 입력
#pragma comment (lib, "winmm.lib")    //음악
#include <mmsystem.h>;                //음악
#include <Digitalv.h>;                //음악

MCI_OPEN_PARMS openBgm;
MCI_PLAY_PARMS playBgm;
MCI_OPEN_PARMS openShuffleSound;
MCI_PLAY_PARMS playShuffleSound;
#define BGM "C:\\BGM.mp3"    //BGM 경로 지정
#define SHUFFLE "C:\\shuffle.mp3"    //효과음 경로 지정
int dwID;

void playingBgm(void) {
    openBgm.lpstrElementName = BGM;            //파일 오픈
    openBgm.lpstrDeviceType = "mpegvideo";    //mp3 형식
    mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD)(LPVOID)&openBgm);
    dwID = openBgm.wDeviceID;
    mciSendCommand(dwID, MCI_PLAY, MCI_DGV_PLAY_REPEAT, (DWORD)(LPVOID)&openBgm);    //음악 반복 재생
}
void playingShuffleSound(void) {
    openShuffleSound.lpstrElementName = SHUFFLE;    //파일 오픈
    openShuffleSound.lpstrDeviceType = "mpegvideo";    //mp3 형식
    mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD)(LPVOID)&openShuffleSound);
    dwID = openShuffleSound.wDeviceID;
    mciSendCommand(dwID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPVOID)&openShuffleSound);    //음악을 한 번 재생
    Sleep(1800);    //효과음이 재생될 때까지 정지했다가
    mciSendCommand(dwID, MCI_SEEK, MCI_SEEK_TO_START, (DWORD)(LPVOID)NULL);    //음원 재생 위치를 처음으로 초기화
}

 

원하는 동작은 BGM이 실행되는 도중 특정한 상황에서 효과음이 들리도록 하는 것이다.

그래서 음악 재생을 별도의 함수로 구현했다.

 

#include <windows.h>    //키보드 입력
#pragma comment (lib, "winmm.lib")    //음악
#include <mmsystem.h>;                //음악
#include <Digitalv.h>;                //음악

 

PlaySound와 마찬가지로 winmm.lib를 추가하고, mmsystem.h헤더 파일을 추가하면 된다. 추가적으로 Digitalv 헤더파일도 필요하다.

 

MCI_OPEN_PARMS openBgm;
MCI_PLAY_PARMS playBgm;
MCI_OPEN_PARMS openShuffleSound;
MCI_PLAY_PARMS playShuffleSound;
#define BGM "C:\\BGM.mp3"    //BGM 경로 지정
#define SHUFFLE "C:\\shuffle.mp3"    //효과음 경로 지정
int dwID;

 

MCI_OPEN_PARMSMCI_OPEN 커맨드를 위한 정보가 담긴 구조체이다.

 

MCIERROR mciSendCommand(
  MCIDEVICEID wDeviceID, 
  MCI_OPEN, 
  DWORD dwFlags, 
  (DWORD) (LPMCI_OPEN_PARMS) lpOpen
);

 

여기서 lpOpen 위치에 MCI_OPEN_PARMS가 들어간다.

MIC_PLAY_PARMS는 재생할 위치 정보를 담고 있는 구조체이다.

BGM을 재생하기 위해 openBgmplayBgm이라는 두 구조체를 선언했고,

효과음을 재생하기 위해 openShuffleSoundplayShuffleSound라는 두 구조체를 선언했다.

 

파일 이름은 경로를 포함해야 하므로 길어질 수 있어서 #define으로 경로를 간단하게 표현했다.

dwIDMCI_OPEN_PARMS이 담고 있는 wDeviceID를 받기 위한 변수다.

이제 BGM을 재생하는 함수를 살펴보자.

 

void playingBgm(void) {
    openBgm.lpstrElementName = BGM;            //파일 오픈
    openBgm.lpstrDeviceType = "mpegvideo";    //mp3 형식
    mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD)(LPVOID)&openBgm);
    dwID = openBgm.wDeviceID;
    mciSendCommand(dwID, MCI_PLAY, MCI_DGV_PLAY_REPEAT, (DWORD)(LPVOID)&openBgm);    //음악 반복 재생
}

 

MIC_OPEN_PARMS 구조체 내의 lpstrElementName은 "Device element (often a path)"라고 설명되어 있다. 재생하고 싶은 파일의 경로를 지정하면 된다.

lpstrDeviceType을 "mpegvideo"로 지정하면 mp3 파일을 이용할 수 있게 된다.

 

MCIERROR mciSendCommand(
   MCIDEVICEID IDDevice,
   UINT        uMsg,
   DWORD_PTR   fdwCommand,
   DWORD_PTR   dwParam
);

 

mciSendCommand 함수는 네 가지 인수가 있다.

IDDevice는 디바이스 식별자로 mci open 메시지인 경우 NULL로 처리한다.

uMsg에는 커맨드를 주고, fdwCommand에 주는 인자에 대해서는

docs.microsoft.com/ko-kr/windows/win32/multimedia/mci-open

 

MCI_OPEN command (Mmsystem.h) - Win32 apps

The MCI\_OPEN command initializes a device or file. All devices recognize this command.

docs.microsoft.com

이 페이지를 참고하면 된다.

 

우리가 세팅한 것이 이름과 형식이기 때문에 MIC_OPEN_ELEMENTMCI_OPEN_TYPE을 주었다.

dwParam은 정보를 담고 있는 구조체를 가리킨다.

 

재생 역시 mciSendCommand를 이용한다.

이번엔 MCI_OPEN 대신 MCI_PLAY를 사용한다.

PLAY에 대해선

docs.microsoft.com/ko-kr/windows/win32/multimedia/mci-play

 

MCI_PLAY command (Mmsystem.h) - Win32 apps

The MCI\_PLAY command signals the device to begin transmitting output data. CD audio, digital-video, MIDI sequencer, videodisc, VCR, and waveform-audio devices recognize this command.

docs.microsoft.com

이 페이지를 참고하면 되겠다.

 

효과음을 재생하는 함수 역시 마찬가지로 설정하면 된다. 조금 다른 점은 원하는 타이밍에 실행해야 한다는 것.

 

void playingShuffleSound(void) {
    openShuffleSound.lpstrElementName = SHUFFLE;    //파일 오픈
    openShuffleSound.lpstrDeviceType = "mpegvideo";    //mp3 형식
    mciSendCommand(0, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD)(LPVOID)&openShuffleSound);
    dwID = openShuffleSound.wDeviceID;
    mciSendCommand(dwID, MCI_PLAY, MCI_NOTIFY, (DWORD)(LPVOID)&openShuffleSound);    //음악을 한 번 재생
    Sleep(1800);    //효과음이 재생될 때까지 정지했다가
    mciSendCommand(dwID, MCI_SEEK, MCI_SEEK_TO_START, (DWORD)(LPVOID)NULL);    //음원 재생 위치를 처음으로 초기화
}

그런데 음악이 한 번 재생되면 재생위치를 기억하기 때문에, 다시 효과음을 사용하려면 재생 위치를 처음으로 바꾸어야 한다. 마지막 코드를 추가하면 된다.

 

또 하나 문제는 효과음을 재생하고 처음 위치로 되돌리는 커맨드가 이어서 실행되면 아무 소리도 들리지 않는다는 것이다. 내가 추측할 때는 재생되자마자 정지버튼을 누르는 상황인 것 같다. 그래서, 효과음 파일이 재생되는 동안(약 1.8초, 파일마다 다름) Sleep을 통해 잠시 진행을 멈춘 후에 실행되도록 했다.

 

 

 

블랙잭 게임(조별과제였다.)에서 카드를 섞는 효과음을 주기 위해서 이름을 shuffle로 지었다.

잘 실행된다.