336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
이번에는 웨이브 출력에 따라 콜백함수를 선언해 호출되도록 하겠습니다. (첨부파일:main.zip)
#pragma comment(lib, "winmm.lib") #include <windows.h> #include <stdio.h> #include <string.h> #include <locale.h> #include <assert.h> #include <conio.h> #include <tchar.h> #pragma pack(push, 1) typedef struct { CHAR szChunkID[4]; // 항상 'R', 'I', 'F', 'F'라는 4개의 ASCII 문자가 옵니다. DWORD dwChunkSize; // 이 필드 바로 다음부터 파일의 맨 끝까지의 크기를 저장합니다. CHAR dwFormat[4]; // 이 필드 다음에 오는 형식의 종류를 지정합니다. 여기에서는 'W', 'A', 'V', 'E'의 4개의 ASCII 문자가 옵니다. } RIFF_HEADER; #pragma pack(pop) #pragma pack(push, 1) typedef struct { CHAR szChunkID[4]; // 항상 'f', 'm', 't', ' '라는 4개의 ASCII 문자가 옵니다. 맨 마지막 글자는 공백(0x20)입니다. DWORD dwChunkSize; // 이 필드 바로 다음부터 파일의 맨 끝까지의 크기를 저장합니다. WORD wFormatTag; // 데이터의 종류를 지정합니다. PCM 형식은 1입니다. WORD nChannels; // 채널의 수를 지정합니다. DWORD nSamplesPerSec; // 초당 샘플링 회수를 지정합니다. DWORD nAvgBytesPerSec; // 1초당 소리 크기를 바이트 수로 지정합니다. WORD nBlockAlign; // 채널의 총 수를 고려하여 sample 1회당 바이트 수를 나타낸 것입니다. WORD wBitsPerSample; // 1개 채널당 sample 1회당 바이트 수를 나타낸 것입니다. } RIFF_FORMAT; #pragma pack(pop) #pragma pack(push, 1) typedef struct { CHAR szChunkID[4]; // 항상 'd', 'a', 't', 'a'라는 4개의 ASCII 문자가 옵니다. DWORD dwChunkSize; // 이 필드 바로 다음부터 파일의 맨 끝까지의 크기를 저장합니다. 헤더 정보를 뺀 순수 데이터의 크기입니다. } RIFF_DATA; #pragma pack(pop) RIFF_HEADER riffHeader; RIFF_FORMAT riffFormat; RIFF_DATA riffData; void CALLBACK WaveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { static WAVEHDR waveHeader; switch (uMsg) { case WOM_OPEN: // waveOutOpen 함수가 실행되었을 경우에는 여기 부분이 처리 _tprintf(TEXT("waveOutProc: WOM_OPEN\n")); break; case WOM_DONE: // waveOutWrite 함수로 작성한 데이터의 재생이 완료되었을 경우에는 여기 부분이 처리 _tprintf(TEXT("waveOutProc: WOM_DONE\n")); break; case WOM_CLOSE: // waveOutClose 함수가 실행되었을 경우에는 여기 부분이 처리 _tprintf(TEXT("waveOutProc: WOM_CLOSE\n")); break; default: break; } } int main(int argc, char * argv[]) { TCHAR szWaveFile[MAX_PATH]; HANDLE hWaveFile = NULL; DWORD dwWaveFileSize = 0; DWORD dwWaveFileRead = 0; DWORD dwWaveData = 0; HGLOBAL hWaveData = NULL; LPBYTE lpWaveData = NULL; HWAVEOUT hWaveOut = NULL; WAVEFORMATEX waveFormatEx; DWORD dwDelay = 0; WAVEHDR waveHeader; _tsetlocale(LC_ALL, TEXT("")); _tcscpy(szWaveFile, TEXT("track01.wav")); hWaveFile = CreateFile(szWaveFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); assert(hWaveFile != NULL); { dwWaveFileSize = GetFileSize(hWaveFile, NULL); assert(dwWaveFileSize > 0); } CloseHandle(hWaveFile); hWaveData = GlobalAlloc(GMEM_MOVEABLE, dwWaveFileSize); assert(hWaveData != NULL); { // 파일을 읽어 메모리에 복사하기 lpWaveData = GlobalLock(hWaveData); assert(lpWaveData); hWaveFile = CreateFile(szWaveFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); assert(hWaveFile != NULL); { SetFilePointer(hWaveFile, 0, NULL, SEEK_SET); ReadFile(hWaveFile, lpWaveData, dwWaveFileSize, &dwWaveFileRead, NULL); assert(dwWaveFileSize == dwWaveFileRead); } assert(CloseHandle(hWaveFile) != 0); assert(GlobalUnlock(hWaveData) == 0); // 헤더 부분을 읽어 구조체로 복사하기 lpWaveData = GlobalLock(hWaveData); assert(lpWaveData != NULL); { CopyMemory(&riffHeader, lpWaveData, sizeof(RIFF_HEADER)); lpWaveData += sizeof(RIFF_HEADER); CopyMemory(&riffFormat, lpWaveData, sizeof(RIFF_FORMAT)); lpWaveData += sizeof(RIFF_FORMAT); CopyMemory(&riffData, lpWaveData, sizeof(RIFF_DATA)); lpWaveData += sizeof(RIFF_DATA); } assert(GlobalUnlock(hWaveData) == 0); // 웨이브 출력 장치 열기 lpWaveData = GlobalLock(hWaveData); assert(lpWaveData != NULL); { // 읽은 데이터 중 일부를 WAVEFORMAT 구조체로 옮김 waveFormatEx.nAvgBytesPerSec = riffFormat.nAvgBytesPerSec; waveFormatEx.nBlockAlign = riffFormat.nBlockAlign; waveFormatEx.nChannels = riffFormat.nChannels; waveFormatEx.nSamplesPerSec = riffFormat.nSamplesPerSec; waveFormatEx.wFormatTag = riffFormat.wFormatTag; waveFormatEx.wBitsPerSample = riffFormat.wBitsPerSample; waveFormatEx.cbSize = 0; // 소리 출력 장치를 열기 assert(waveOutOpen(&hWaveOut, WAVE_MAPPER, &waveFormatEx, (DWORD)WaveOutProc, (DWORD)lpWaveData, CALLBACK_FUNCTION) == MMSYSERR_NOERROR); { // 1 [sec]당 소요된 바이트 수를 구합니다. // (1회 샘플크기[비트] / 8) * (1[sec]당 샘플 회수) * (채널 수:1=모노, 2=스테레오) dwDelay = (riffFormat.wBitsPerSample / 8) * riffFormat.nSamplesPerSec * riffFormat.nChannels; _tprintf(TEXT("bytesPerSec = %d\n"), dwDelay); // 프로그램이 종료되는 것을 지연시키는 시간을 구합니다. // ("data"로 시작하는 구조체의 dwChunkSize값[바이트]) / (1[sec]당 소요된 바이트) dwDelay = riffData.dwChunkSize / dwDelay; _tprintf(TEXT("TotalSec = %d (%02d:%02d)\n"), dwDelay, (dwDelay / 60), (dwDelay % 60)); waveHeader.lpData = (LPVOID)lpWaveData; // 소리 데이터가 있는 위치 waveHeader.dwBufferLength = riffData.dwChunkSize; // 소리 데이터의 크기 waveHeader.dwBytesRecorded = 0; waveHeader.dwFlags = 0L; waveHeader.dwLoops = 0L; waveHeader.dwUser = 0; waveHeader.lpNext = NULL; waveHeader.reserved = 0L; waveOutPrepareHeader(hWaveOut, &waveHeader, sizeof(WAVEHDR)); { waveOutWrite(hWaveOut, &waveHeader, sizeof(WAVEHDR)); // 소리가 완전히 끝날때까지 프로그램 종료를 지연 (1000[msec]의 여유 시분을 더 추가함) Sleep(dwDelay * 1000 + 1000); } waveOutUnprepareHeader(hWaveOut, &waveHeader, sizeof(WAVEHDR)); } assert(waveOutClose(hWaveOut) == MMSYSERR_NOERROR); } assert(GlobalUnlock(hWaveData) == 0); } assert(GlobalFree(hWaveData) == NULL); _tprintf(TEXT("END")); _getch(); return 0; }
실행결과: WOM_OPEN과 WOM_DONE 문장 사이에 사운드가 출력됩니다.
'Application Programming Interface > Windows API' 카테고리의 다른 글
Visual C++로 MSXML 사용하기 #2 (2) | 2014.08.11 |
---|---|
Visual C++로 MSXML 사용하기 #1 (1) | 2014.08.11 |
waveOut 함수 사용 예제 #1 (0) | 2014.05.14 |
갈아 만든 Windows API - #3 Hello, World! (0) | 2011.08.15 |
갈아 만든 Windows API - #2. 창 배경색 수정하기 (0) | 2011.08.15 |