home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / Source / GPCHAP13 / PROG13_2.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2002-04-29  |  9.7 KB  |  343 lines

  1. // PROG13_2.CPP - Making a simple sound with DirectSound
  2. // makes a 500hz tone, try changing it for fun!
  3.  
  4. // INCLUDES ///////////////////////////////////////////////
  5. #define WIN32_LEAN_AND_MEAN  
  6. #define INITGUID
  7.  
  8. #include <windows.h>   // include important windows stuff
  9. #include <windowsx.h> 
  10. #include <mmsystem.h>
  11. #include <iostream.h> // include important C/C++ stuff
  12. #include <conio.h>
  13. #include <stdlib.h>
  14. #include <malloc.h>
  15. #include <memory.h>
  16. #include <string.h>
  17. #include <stdarg.h>
  18. #include <stdio.h>
  19. #include <math.h>
  20. #include <io.h>
  21. #include <fcntl.h>
  22.  
  23. #include <ddraw.h>  // directX includes
  24. #include <dsound.h>
  25.  
  26. // DEFINES ////////////////////////////////////////////////
  27.  
  28. // directx 7+ compatibility, MS got rid of this constant, but I like it
  29. #ifndef DSBCAPS_CTRLDEFAULT
  30. #define DSBCAPS_CTRLDEFAULT (DSBCAPS_CTRLFREQUENCY | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME )
  31. #endif
  32.  
  33.  
  34. // defines for windows 
  35. #define WINDOW_CLASS_NAME "WINXCLASS"  // class name
  36.  
  37. #define WINDOW_WIDTH  320              // size of window
  38. #define WINDOW_HEIGHT 240
  39. #define SCREEN_WIDTH  640              // size of screen
  40. #define SCREEN_HEIGHT 480
  41. #define SCREEN_BPP    8                // bits per pixel
  42.  
  43. // MACROS /////////////////////////////////////////////////
  44.  
  45. // these read the keyboard asynchronously
  46. #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
  47. #define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
  48.  
  49. // TYPES //////////////////////////////////////////////////
  50.  
  51. typedef unsigned short USHORT;
  52. typedef unsigned short WORD;
  53. typedef unsigned char  UCHAR;
  54. typedef unsigned char  BYTE;
  55.  
  56. // PROTOTYPES /////////////////////////////////////////////
  57.  
  58. int Game_Init(void *parms=NULL);
  59. int Game_Shutdown(void *parms=NULL);
  60. int Game_Main(void *parms=NULL);
  61.  
  62. // GLOBALS ////////////////////////////////////////////////
  63.  
  64. HWND main_window_handle = NULL; // save the window handle
  65. HINSTANCE main_instance = NULL; // save the instance
  66. char buffer[80];                // used to print text
  67.  
  68. LPDIRECTSOUND            lpds;           // directsound interface pointer
  69. DSBUFFERDESC            dsbd;           // directsound description
  70. DSCAPS                  dscaps;         // directsound caps
  71. HRESULT                 dsresult;       // general directsound result
  72. DSBCAPS                 dsbcaps;        // directsound buffer caps
  73.  
  74. LPDIRECTSOUNDBUFFER    lpdsbprimary,    // you won't need this normally
  75.                        lpdsbsecondary;  // the sound buffers
  76.  
  77. WAVEFORMATEX            pcmwf;          // generic waveformat structure
  78.               
  79. // FUNCTIONS //////////////////////////////////////////////
  80.  
  81. LRESULT CALLBACK WindowProc(HWND hwnd, 
  82.                             UINT msg, 
  83.                             WPARAM wparam, 
  84.                             LPARAM lparam)
  85. {
  86. // this is the main message handler of the system
  87. PAINTSTRUCT    ps;           // used in WM_PAINT
  88. HDC            hdc;       // handle to a device context
  89.  
  90. // what is the message 
  91. switch(msg)
  92.     {    
  93.     case WM_CREATE: 
  94.         {
  95.         // do initialization stuff here
  96.         return(0);
  97.         } break;
  98.  
  99.     case WM_PAINT:
  100.          {
  101.          // start painting
  102.          hdc = BeginPaint(hwnd,&ps);
  103.  
  104.          // end painting
  105.          EndPaint(hwnd,&ps);
  106.          return(0);
  107.         } break;
  108.  
  109.     case WM_DESTROY: 
  110.         {
  111.         // kill the application            
  112.         PostQuitMessage(0);
  113.         return(0);
  114.         } break;
  115.  
  116.     default:break;
  117.  
  118.     } // end switch
  119.  
  120. // process any messages that we didn't take care of 
  121. return (DefWindowProc(hwnd, msg, wparam, lparam));
  122.  
  123. } // end WinProc
  124.  
  125. // WINMAIN ////////////////////////////////////////////////
  126.  
  127. int WINAPI WinMain(    HINSTANCE hinstance,
  128.                     HINSTANCE hprevinstance,
  129.                     LPSTR lpcmdline,
  130.                     int ncmdshow)
  131. {
  132.  
  133. WNDCLASS winclass;    // this will hold the class we create
  134. HWND     hwnd;        // generic window handle
  135. MSG      msg;           // generic message
  136. HDC      hdc;       // generic dc
  137. PAINTSTRUCT ps;     // generic paintstruct
  138.  
  139. // first fill in the window class stucture
  140. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  141.                           CS_HREDRAW | CS_VREDRAW;
  142. winclass.lpfnWndProc    = WindowProc;
  143. winclass.cbClsExtra    = 0;
  144. winclass.cbWndExtra    = 0;
  145. winclass.hInstance     = hinstance;
  146. winclass.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  147. winclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
  148. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  149. winclass.lpszMenuName    = NULL; 
  150. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  151.  
  152. // register the window class
  153. if (!RegisterClass(&winclass))
  154.     return(0);
  155.  
  156. // create the window, note the use of WS_POPUP
  157. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  158.                          "WinX Game Console - 500hz Tone",      // title
  159.                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  160.                           0,0,     // x,y
  161.                           WINDOW_WIDTH,  // width
  162.                           WINDOW_HEIGHT, // height
  163.                           NULL,    // handle to parent
  164.                           NULL,    // handle to menu
  165.                           hinstance,// instance
  166.                           NULL)))       // creation parms
  167. return(0);
  168.  
  169. // save the window handle and instance in a global
  170. main_window_handle = hwnd;
  171. main_instance      = hinstance;
  172.  
  173. // perform all game console specific initialization
  174. // start up the directsound sound
  175. Game_Init();
  176.  
  177. // enter main event loop
  178. while(1)
  179.     {
  180.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  181.         { 
  182.         // test if this is a quit
  183.         if (msg.message == WM_QUIT)
  184.            break;
  185.     
  186.         // translate any accelerator keys
  187.         TranslateMessage(&msg);
  188.  
  189.         // send the message to the window proc
  190.         DispatchMessage(&msg);
  191.         } // end if
  192.     
  193.     // main game processing goes here
  194.     Game_Main();
  195.  
  196.     } // end while
  197.  
  198. // shutdown game and release all resources
  199. Game_Shutdown();
  200.  
  201. // return to Windows like this
  202. return(msg.wParam);
  203.  
  204. } // end WinMain
  205.  
  206. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  207.  
  208. int Game_Init(void *parms)
  209. {
  210. // this function is where you do all the initialization 
  211. // for your game
  212.  
  213. // this example does everything: it sets up directsound
  214. // creates a secondary buffer, loads it with a synthesizer
  215. // sine wave and plays it
  216.  
  217. void     *audio_ptr_1 = NULL,   // used to lock memory
  218.         *audio_ptr_2 = NULL;
  219.  
  220. DWORD    dsbstatus;              // status of sound buffer
  221.  
  222. DWORD    audio_length_1    = 0,  // length of locked memory
  223.         audio_length_2    = 0,
  224.         snd_buffer_length = 64000; // working buffer
  225.  
  226. // allocate memory for buffer
  227. UCHAR *snd_buffer_ptr = (UCHAR *)malloc(snd_buffer_length);
  228.  
  229. // we need some data for the buffer, you could load a .VOC or .WAV
  230. // but as an example, lets synthesize the data
  231.  
  232. // fill buffer with a synthesized 500hz sine wave
  233. for (int index=0; index < (int)snd_buffer_length; index++)
  234.     snd_buffer_ptr[index] = 127*sin(6.28*((float)(index%22))/(float)22);
  235.     
  236. // note the math, 127 is the scale or amplitude
  237. // 6.28 is to convert to radians
  238. // (index % 22) read below
  239. // we are playing at 11025 hz or 11025 cycles/sec therefore, in 1 sec
  240. // we want 100 cycles of our synthesized sound, thus 11025/500 is approx.
  241. // 22, thus we want the waveform to repeat each 22 clicks of index, so
  242. // normalize to 22
  243.  
  244.  
  245. // create a directsound object
  246. if (DirectSoundCreate(NULL, &lpds, NULL)!=DS_OK )
  247.     return(0);
  248.  
  249. // set cooperation level
  250. if (lpds->SetCooperativeLevel(main_window_handle,DSSCL_NORMAL)!=DS_OK)
  251.     return(0);
  252.  
  253. // set up the format data structure
  254. memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
  255.  
  256. pcmwf.wFormatTag      = WAVE_FORMAT_PCM;
  257. pcmwf.nChannels          = 1;
  258. pcmwf.nSamplesPerSec  = 11025;
  259. pcmwf.nBlockAlign      = 1;
  260. pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
  261. pcmwf.wBitsPerSample  = 8;
  262. pcmwf.cbSize          = 0;
  263.  
  264. // create the secondary buffer (no need for a primary)
  265. memset(&dsbd,0,sizeof(DSBUFFERDESC));
  266. dsbd.dwSize            = sizeof(DSBUFFERDESC);
  267. dsbd.dwFlags        = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE;
  268. dsbd.dwBufferBytes    = snd_buffer_length+1;
  269. dsbd.lpwfxFormat    = &pcmwf;
  270.  
  271. if (lpds->CreateSoundBuffer(&dsbd,&lpdsbsecondary,NULL)!=DS_OK)
  272.     return(0);
  273.  
  274. // copy data into sound buffer
  275. if (lpdsbsecondary->Lock(0,                     
  276.                       snd_buffer_length,            
  277.                       &audio_ptr_1, 
  278.                       &audio_length_1,
  279.                       &audio_ptr_2, 
  280.                       &audio_length_2,
  281.                       DSBLOCK_FROMWRITECURSOR)!=DS_OK)
  282.   return(0);
  283.  
  284. // copy first section of circular buffer
  285. CopyMemory(audio_ptr_1, snd_buffer_ptr, audio_length_1);
  286.  
  287. // copy last section of circular buffer
  288. CopyMemory(audio_ptr_2, (snd_buffer_ptr+audio_length_1),audio_length_2);
  289.  
  290. // unlock the buffer
  291. if (lpdsbsecondary->Unlock(audio_ptr_1, 
  292.                            audio_length_1, 
  293.                            audio_ptr_2, 
  294.                            audio_length_2)!=DS_OK)
  295.     return(0);
  296.  
  297. // play the sound in looping mode
  298. if (lpdsbsecondary->Play(0,0,DSBPLAY_LOOPING )!=DS_OK)
  299.     return(0);
  300.  
  301. // release the memory since DirectSound has made a copy of it
  302. free(snd_buffer_ptr);
  303.  
  304. // return success
  305. return(1);
  306.  
  307. } // end Game_Init
  308.  
  309. ///////////////////////////////////////////////////////////
  310.  
  311. int Game_Shutdown(void *parms)
  312. {
  313. // this function is where you shutdown your game and
  314. // release all resources that you allocated
  315.  
  316. // release the directsoundobject
  317. if (lpds!=NULL)
  318.    lpds->Release();
  319.  
  320.  
  321. // return success
  322. return(1);
  323. } // end Game_Shutdown
  324.  
  325. ///////////////////////////////////////////////////////////
  326.  
  327. int Game_Main(void *parms)
  328. {
  329. // this is the workhorse of your game it will be called
  330. // continuously in real-time this is like main() in C
  331. // all the calls for you game go here!
  332.  
  333. // check of user is trying to exit
  334. if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
  335.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  336.  
  337. // return success
  338. return(1);
  339. } // end Game_Main
  340.  
  341. ///////////////////////////////////////////////////////////
  342.  
  343.