#define _STLP_NEW_PLATFORM_SDK 1
#include <windows.h>
#include <dinput.h>
#include <stdio.h>
#include <dsound.h>
char c_szClassName[] = "사운드출력" ;
HINSTANCE g_hInst ;
BOOL g_bPaused = TRUE ;
LPDIRECTINPUT g_lpDirectInput ;
LPDIRECTINPUTDEVICE g_lpKeyboard ;
char g_szText[1024] = "00" ;
int X_pos, Y_pos ;
#define KEYDOWN(State,KeyID) (State[KeyID] & 0x80)
#ifdef DS
#define NUM_SOUNDS 5
#define SPACE 0
#define LEFT 1
#define RIGHT 2
#define UP 3
#define DOWN 4
HWND g_hWnd = NULL ;
LPDIRECTSOUND g_lpDirectSound = NULL ;
LPDIRECTSOUNDBUFFER g_lpSoundBuffer[NUM_SOUNDS] ;
#ifdef _3DS
LPDIRECTSOUND3DLISTENER g_lpDirectSound3dListener ;
LPDIRECTSOUNDBUFFER g_lpDirectSoundBuffer ;
LPDIRECTSOUND3DBUFFER g_lp3DSoundBuffer[NUM_SOUNDS] ;
#endif
#pragma pack(1)
struct WaveHeader
{
BYTE RIFF[4]; // "RIFF"
DWORD dwSize; // Size of data to follow
BYTE WAVE[4]; // "WAVE"
BYTE fmt_[4]; // "fmt "
DWORD dw16; // 16
WORD wOne_0; // 1
WORD wChnls; // Number of Channels
DWORD dwSRate; // Sample Rate
DWORD BytesPerSec; // Sample Rate
WORD wBlkAlign; // 1
WORD BitsPerSample; // Sample size
BYTE DATA[4]; // "DATA"
DWORD dwDSize; // Number of Samples
};
#pragma pack()
#ifdef _3DS
//----------------------------------------------------------------------
//
// Function : CreateSoundBuffer3D()
//
// Purpose : Creates a 3D sound buffer and returns the sound buffer
//
//----------------------------------------------------------------------
/****************************************************************************
*
* CreateSoundBuffer3D
*
* 3D 사운드 버퍼를 생성하고 그 값을 리턴한다.
*
****************************************************************************/
IDirectSoundBuffer *CreateSoundBuffer3D ()
{
IDirectSoundBuffer *lpDirectSoundBuffer = NULL ;
DSBUFFERDESC dsbDesc = {0} ;
HRESULT hResult ;
ZeroMemory (&dsbDesc, sizeof (DSBUFFERDESC)) ;
dsbDesc.dwSize = sizeof (dsbDesc) ;
dsbDesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER ;
dsbDesc.dwBufferBytes = 0 ;
hResult = g_lpDirectSound->CreateSoundBuffer
(&dsbDesc, &lpDirectSoundBuffer, NULL) ;
if (hResult != DS_OK)
lpDirectSoundBuffer = NULL ;
return lpDirectSoundBuffer ;
}
#endif
/****************************************************************************
*
* PlaySoundDS
*
* DirectSound를 이용하여 사운드를 출력시킨다.
*
****************************************************************************/
BOOL PlaySoundDS (DWORD dwSound, D3DVECTOR d3dvPos, DWORD dwFlags)
{
HRESULT hResult ;
DWORD dwStatus ;
if (dwSound >= NUM_SOUNDS)
return FALSE ;
if (g_lpSoundBuffer[dwSound])
{
hResult = g_lpSoundBuffer[dwSound]->GetStatus (&dwStatus) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "GetStatus 에러", "사운드출력", MB_OK) ;
return FALSE;
}
if ((dwStatus & DSBSTATUS_PLAYING) != DSBSTATUS_PLAYING)
{
#ifdef _3DS
hResult = g_lp3DSoundBuffer[dwSound]->SetPosition
(d3dvPos.x, d3dvPos.y, d3dvPos.z, DS3D_IMMEDIATE) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "SetPosition 에러", "사운드출력", MB_OK) ;
return FALSE;
}
#endif
hResult = g_lpSoundBuffer[dwSound]->Play (0, 0, dwFlags) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "Play 에러", "사운드출력", MB_OK) ;
return FALSE;
}
}
}
return TRUE ;
}
/****************************************************************************
*
* OutputSound
*
* Sound를 출력한다.
*
****************************************************************************/
void OutputSound (DWORD dwSound)
{
D3DVECTOR d3dvPos ;
d3dvPos.x = D3DVAL(0) ;
d3dvPos.y = D3DVAL(0) ;
d3dvPos.z = D3DVAL(0) ;
PlaySoundDS (dwSound, d3dvPos, NULL) ;
}
/****************************************************************************
*
* ReadData
*
* 웨이브(*.wav) 화일로부터 데이타를 읽어들인다.
*
****************************************************************************/
BOOL ReadData (LPDIRECTSOUNDBUFFER lpSoundBuffer,
FILE* pFile, DWORD dwSize, DWORD dwPos)
{
LPVOID lpData1 ;
DWORD dwData1Size ;
LPVOID lpData2 ;
DWORD dwData2Size ;
HRESULT hResult ;
if (dwPos != 0xffffffff)
{
if (fseek (pFile, dwPos, SEEK_SET) != 0)
{
return FALSE ;
}
}
hResult = lpSoundBuffer->Lock (0, dwSize, &lpData1, &dwData1Size,
&lpData2, &dwData2Size, DSBLOCK_FROMWRITECURSOR);
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "Lock 에러", "사운드출력", MB_OK) ;
return FALSE;
}
if (dwData1Size > 0)
{
if (fread (lpData1, dwData1Size, 1, pFile) != 1)
{
char holder[256] ;
wsprintf (holder, "Data1 : %d, dwdata: %d, pFile: %d",
lpData1, dwData1Size, pFile) ;
MessageBox (g_hWnd, holder, "사운드출력", MB_OK) ;
return FALSE ;
}
}
if (dwData2Size > 0)
{
if (fread (lpData2, dwData2Size, 1, pFile) != 1)
{
MessageBox (g_hWnd, "fread::lpData2 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
}
hResult = lpSoundBuffer->Unlock (lpData1, dwData1Size, lpData2, dwData2Size) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "Unlock 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
return TRUE ;
}
/****************************************************************************
*
* CreateSoundBuffer
*
* DirectSound 버퍼를 생성한다.
*
****************************************************************************/
BOOL CreateSoundBuffer (DWORD dwBuf, DWORD dwBufSize, DWORD dwFreq,
DWORD dwBitsPerSample, DWORD dwBlkAlign, BOOL bStereo)
{
PCMWAVEFORMAT pcmwf ;
DSBUFFERDESC dsbdesc ;
HRESULT hResult ;
memset (&pcmwf, 0, sizeof (PCMWAVEFORMAT)) ;
pcmwf.wf.wFormatTag = WAVE_FORMAT_PCM ;
pcmwf.wf.nChannels = bStereo ? 2 : 1 ;
pcmwf.wf.nSamplesPerSec = dwFreq ;
pcmwf.wf.nBlockAlign = (WORD)dwBlkAlign ;
pcmwf.wf.nAvgBytesPerSec = pcmwf.wf.nSamplesPerSec * pcmwf.wf.nBlockAlign ;
pcmwf.wBitsPerSample = (WORD)dwBitsPerSample ;
memset (&dsbdesc, 0, sizeof (DSBUFFERDESC)) ;
dsbdesc.dwSize = sizeof (DSBUFFERDESC) ;
dsbdesc.dwFlags = 0 ;
#ifdef _3DS
dsbdesc.dwFlags = DSBCAPS_CTRL3D ;
#else
dsbdesc.dwFlags |= DSBCAPS_STATIC ;
dsbdesc.dwFlags |= DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2 ;
#endif
dsbdesc.dwBufferBytes = dwBufSize ;
dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&pcmwf ;
hResult = g_lpDirectSound->CreateSoundBuffer
(&dsbdesc, &g_lpSoundBuffer[dwBuf], NULL) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "CreateSoundBuffer 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
#ifdef _3DS
hResult = g_lpSoundBuffer[dwBuf]->QueryInterface
(IID_IDirectSound3DBuffer, (void**) &g_lp3DSoundBuffer[dwBuf]) ;
if (hResult != DS_OK)
{
MessageBox (g_hWnd, "QueryInterface<-CreateSoundBuffer 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
#endif
return TRUE ;
}
/****************************************************************************
*
* CreateSoundBufferFromWaveFile
*
* 웨이브(.wav)화일읽 읽어들여와 DirectSound 버퍼를 생성한다.
*
****************************************************************************/
BOOL CreateBufferFromWaveFile (char* FileName, DWORD dwBuf)
{
WaveHeader wavHdr;
DWORD dwSize ;
BOOL bStereo ;
FILE *pFile ;
pFile = fopen (FileName,"rb") ;
if (pFile == NULL)
return FALSE ;
if (fread (&wavHdr, sizeof (wavHdr), 1, pFile) != 1)
{
fclose (pFile) ;
return NULL ;
}
dwSize = wavHdr.dwDSize ;
bStereo = wavHdr.wChnls > 1 ? TRUE : FALSE ;
if (!CreateSoundBuffer (dwBuf, dwSize, wavHdr.dwSRate,
wavHdr.BitsPerSample, wavHdr.wBlkAlign, bStereo))
{
fclose (pFile) ;
return FALSE ;
}
if (!ReadData (g_lpSoundBuffer[dwBuf], pFile, dwSize, sizeof (wavHdr)))
{
fclose (pFile) ;
return FALSE ;
}
fclose (pFile) ;
return TRUE ;
}
#endif
/****************************************************************************
*
* DirectInput_Init
*
* DirectInput에 대한 초기화를 수행한다.
*
* 다음 순서대로 함수를 호출한다.
*
* DirectInputCreate
* IDirectInput::CreateDevice
* IDirectInputDevice::SetDataFormat
* IDirectInputDevice::SetCooperativeLevel
*
****************************************************************************/
BOOL DirectInput_Init (HWND hwnd)
{
HRESULT hResult ;
hResult = DirectInputCreate (g_hInst, DIRECTINPUT_VERSION, &g_lpDirectInput, NULL) ;
if (hResult != DI_OK)
{
MessageBox (hwnd, "DirectInputCreate 에러", "키보드입력", MB_OK) ;
return FALSE ;
}
hResult = g_lpDirectInput->CreateDevice (GUID_SysKeyboard, &g_lpKeyboard, NULL) ;
if (hResult != DI_OK)
{
MessageBox (hwnd, "CreateDevice 에러", "키보드입력", MB_OK) ;
return FALSE ;
}
hResult = g_lpKeyboard->SetDataFormat (&c_dfDIKeyboard) ;
if (hResult != DI_OK)
{
MessageBox (hwnd, "SetDataFormat 에러", "키보드입력", MB_OK) ;
return FALSE ;
}
hResult = g_lpKeyboard->SetCooperativeLevel
(hwnd, DISCL_NONEXCLUSIVE | DISCL_FOREGROUND) ;
if (hResult != DI_OK)
{
MessageBox (hwnd, "SetCooperativeLevel 에러", "키보드입력", MB_OK) ;
return FALSE ;
}
#ifdef DS
hResult = DirectSoundCreate (NULL, &g_lpDirectSound, NULL) ;
if (hResult != DS_OK)
{
MessageBox (hwnd, "DirectSoundCreate 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
g_lpDirectSound->SetCooperativeLevel (hwnd, DSSCL_NORMAL) ;
if (hResult != DS_OK)
{
MessageBox (hwnd, "SetCooperativeLevel 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
#ifdef _3DS
g_lpDirectSoundBuffer = CreateSoundBuffer3D () ;
if (g_lpDirectSoundBuffer == NULL)
{
MessageBox (hwnd, "CreateSoundBuffer3D 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
hResult = g_lpDirectSoundBuffer->QueryInterface
(IID_IDirectSound3DListener, (void**) &g_lpDirectSound3dListener) ;
if (hResult != DS_OK)
{
MessageBox (hwnd, "QueryInterface 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
g_lpDirectSound3dListener->SetRolloffFactor ((FLOAT).01,DS3D_DEFERRED) ;
g_lpDirectSound3dListener->SetOrientation (-D3DVAL(1), D3DVAL(0),
D3DVAL(0), D3DVAL(0), D3DVAL(1), D3DVAL(0), DS3D_DEFERRED) ;
g_lpDirectSound3dListener->CommitDeferredSettings () ;
#endif
for (int i = 0; i < NUM_SOUNDS; i ++)
{
g_lpSoundBuffer[i] = NULL ;
}
if (!CreateBufferFromWaveFile ("SPACE.WAV", SPACE))
{
MessageBox (hwnd, "CreateBufferFromWaveFile (SPACE) 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
if (!CreateBufferFromWaveFile ("LEFT.WAV", LEFT))
{
MessageBox (hwnd, "CreateBufferFromWaveFile (LEFT) 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
if (!CreateBufferFromWaveFile ("RIGHT.WAV", RIGHT))
{
MessageBox (hwnd, "CreateBufferFromWaveFile (RIGHT) 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
if (!CreateBufferFromWaveFile ("UP.WAV", UP))
{
MessageBox (hwnd, "CreateBufferFromWaveFile (UP) 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
if (!CreateBufferFromWaveFile ("DOWN.WAV", DOWN))
{
MessageBox (hwnd, "CreateBufferFromWaveFile (DOWN) 에러", "사운드출력", MB_OK) ;
return FALSE ;
}
#endif
return TRUE ;
}
/****************************************************************************
*
* DirectInput_End
*
* 프로그램의 종료시 생성된 DirectInput 객체들을 해제시킨다.
*
****************************************************************************/
void DirectInput_End (void)
{
if (g_lpKeyboard)
{
g_lpKeyboard->Unacquire () ;
g_lpKeyboard->Release () ;
g_lpKeyboard = NULL ;
}
if (g_lpDirectInput)
{
g_lpDirectInput->Release () ;
g_lpDirectInput = NULL ;
}
#ifdef DS
for (int i=0; i<NUM_SOUNDS; i++)
{
if (g_lpSoundBuffer[i])
{
g_lpSoundBuffer[i]->Release () ;
g_lpSoundBuffer[i] = NULL ;
}
}
#ifdef _3DS
for (i=0; i<NUM_SOUNDS; i++)
{
if (g_lp3DSoundBuffer[i])
{
g_lp3DSoundBuffer[i]->Release () ;
g_lp3DSoundBuffer[i] = NULL ;
}
}
if (g_lpDirectSound3dListener)
{
g_lpDirectSound3dListener->Release () ;
g_lpDirectSound3dListener = NULL ;
}
if (g_lpDirectSoundBuffer)
{
g_lpDirectSoundBuffer->Release () ;
g_lpDirectSoundBuffer = NULL ;
}
#endif
if (g_lpDirectSound)
{
g_lpDirectSound->Release () ;
g_lpDirectSound = NULL ;
}
#endif
}
/****************************************************************************
*
* OnPaint
*
* 현재 눌려진 키보드의 상태를 화면상에 보여준다.
*
****************************************************************************/
LRESULT OnPaint (HWND hwnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint (hwnd, &ps) ;
if (hdc)
{
ExtTextOut (hdc, X_pos, Y_pos, ETO_OPAQUE, &ps.rcPaint, g_szText,
lstrlen(g_szText), NULL) ;
EndPaint (hwnd, &ps) ;
}
return 0 ;
}
/****************************************************************************
*
* CheckRect
*
* 현재 x와 y의 좌표가 윈도우를 벗어났는가 확인하고
*
* x와 y의 위치에 키보드 상태를 출력하도록 한다.
*
****************************************************************************/
void CheckRect (HWND hwnd, int *X_pos, int *Y_pos, char *szBuf)
{
RECT rect ;
GetClientRect (hwnd, &rect) ;
if (*X_pos < 0)
*X_pos = 0 ;
if (*Y_pos < 0)
*Y_pos = 0 ;
if (*X_pos > rect.right-10)
*X_pos = rect.right-10 ;
if (*Y_pos > rect.bottom-10)
*Y_pos = rect.bottom-10 ;
lstrcpy (g_szText, szBuf) ;
InvalidateRect (hwnd, NULL, TRUE) ;
}
/****************************************************************************
*
* KeyInput
*
* 현재 입력된 키보드의 상태를 확인한다.
*
****************************************************************************/
void KeyInput (HWND hwnd)
{
if (g_lpKeyboard)
{
BYTE KeyState[256] ;
HRESULT hResult ;
for (;;)
{
hResult = g_lpKeyboard->GetDeviceState (sizeof (KeyState), &KeyState) ;
if (hResult == DIERR_INPUTLOST)
{
hResult = g_lpKeyboard->Acquire () ;
if (hResult != DI_OK)
{
break ;
}
}
else
break ;
}
if (hResult == DI_OK)
{
char szBuf[1024] ;
// 아래 있는 모든 if문을 else if 형태로 묶으면
// 키보드 동시입력을 지원하지 못하게 된다.
// 그러므로 동시에 입력되도록 if 문으로
// 각각의 키를 매순간 모두 비교해야 한다.
if (KEYDOWN(KeyState, DIK_RIGHT))
{
lstrcpy (szBuf, "Right") ;
X_pos+=10 ;
CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
OutputSound (RIGHT) ;
#endif
}
else if (KEYDOWN(KeyState, DIK_LEFT))
{
lstrcpy (szBuf, "Left") ;
X_pos-=10 ;
CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
OutputSound (LEFT) ;
#endif
}
if (KEYDOWN(KeyState, DIK_UP))
{
lstrcpy (szBuf, "Up") ;
Y_pos-=10 ;
CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
OutputSound (UP) ;
#endif
}
else if (KEYDOWN(KeyState, DIK_DOWN))
{
lstrcpy (szBuf, "Down") ;
Y_pos+=10 ;
CheckRect (hwnd, &X_pos, &Y_pos, szBuf) ;
#ifdef DS
OutputSound (DOWN) ;
#endif
}
if (KEYDOWN(KeyState, DIK_ESCAPE))
{
lstrcpy (szBuf, "Esc") ;
lstrcpy (g_szText, szBuf) ;
InvalidateRect (hwnd, NULL, TRUE) ;
}
if (KEYDOWN(KeyState, DIK_SPACE))
{
lstrcpy (szBuf, "SPACE") ;
lstrcpy (g_szText, szBuf) ;
InvalidateRect (hwnd, NULL, TRUE) ;
#ifdef DS
OutputSound (SPACE) ;
#endif
}
if (KEYDOWN(KeyState, DIK_LSHIFT))
{
lstrcpy (szBuf, "LShift") ;
lstrcpy (g_szText, szBuf) ;
InvalidateRect (hwnd, NULL, TRUE) ;
}
if (KEYDOWN(KeyState, DIK_RSHIFT))
{
lstrcpy (szBuf, "RShift") ;
lstrcpy (g_szText, szBuf) ;
InvalidateRect (hwnd, NULL, TRUE) ;
}
}
}
}
/****************************************************************************
*
* SyncAcquire
*
* g_bPaused의 상태에 따라서 Acquire ()를 호출할 것인지
*
* Unacquire ()를 호출할 것인지를 결정한다.
*
****************************************************************************/
void SyncAcquire (HWND hwnd)
{
if (g_bPaused)
{
if (g_lpKeyboard)
g_lpKeyboard->Unacquire () ;
}
else
{
if (g_lpKeyboard)
g_lpKeyboard->Acquire () ;
}
}
/****************************************************************************
*
* WndProc
*
* 윈도우로 입력되는 메세지들을 처리하는 부분
*
****************************************************************************/
LRESULT CALLBACK WndProc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_PAINT:
return OnPaint (hwnd) ;
case WM_ACTIVATE:
if (wParam == WA_INACTIVE)
g_bPaused = TRUE ;
else
g_bPaused = FALSE ;
SyncAcquire (hwnd) ;
break;
case WM_DESTROY:
PostQuitMessage (0) ;
break;
}
return DefWindowProc (hwnd, msg, wParam, lParam) ;
}
/****************************************************************************
*
* AppInit
*
* 윈도우의 생성시 필요한 값들을 초기화한다.
*
****************************************************************************/
HWND AppInit (HINSTANCE hinst, int nCmdShow)
{
g_hInst = hinst ;
WNDCLASS wc ;
wc.hCursor = LoadCursor (0, IDC_ARROW) ;
wc.hIcon = LoadIcon (NULL, MAKEINTRESOURCE(IDI_APPLICATION)) ;
wc.lpszMenuName = NULL ;
wc.lpszClassName = c_szClassName ;
wc.hbrBackground = 0 ;
wc.hInstance = hinst ;
wc.style = 0 ;
wc.lpfnWndProc = WndProc ;
wc.cbClsExtra = 0 ;
wc.cbWndExtra = 0 ;
if (!RegisterClass (&wc))
{
return NULL ;
}
HWND hwnd = CreateWindow (
c_szClassName,
"사운드 입력",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL,
g_hInst,
0
) ;
g_hWnd = hwnd ;
if (!DirectInput_Init (hwnd))
{
DestroyWindow (hwnd) ;
return NULL ;
}
ShowWindow (hwnd, nCmdShow) ;
return hwnd ;
}
/****************************************************************************
*
* WinMain
*
* 윈도우즈의 메인함수.
*
****************************************************************************/
int PASCAL WinMain (HINSTANCE hinst, HINSTANCE hinstPrev, LPSTR szCmdLine, int nCmdShow)
{
MSG msg ;
HWND hwnd = AppInit (hinst, nCmdShow) ;
msg.wParam = 0 ;
X_pos = Y_pos = 0 ;
if (hwnd)
{
for (;;)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
break;
}
else
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
else if (g_bPaused)
{
WaitMessage () ;
}
else
{
KeyInput (hwnd) ;
}
}
}
DirectInput_End () ;
return msg.wParam ;
}