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

  1. // PROG13_3.CPP - Loading and playing a voc file
  2. // with real-time manipulation
  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. #define NVB_SIZE      6 // size of new voice block in bytes
  44.  
  45. // MACROS /////////////////////////////////////////////////
  46.  
  47. // these read the keyboard asynchronously
  48. #define KEY_DOWN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
  49. #define KEY_UP(vk_code)   ((GetAsyncKeyState(vk_code) & 0x8000) ? 0 : 1)
  50.  
  51. // TYPES //////////////////////////////////////////////////
  52.  
  53. typedef unsigned short USHORT;
  54. typedef unsigned short WORD;
  55. typedef unsigned char  UCHAR;
  56. typedef unsigned char  BYTE;
  57.  
  58. // this structure holds a loaded sound
  59. typedef struct VOC_FILE_TYP
  60.         {
  61.         int sample_rate; // sample rate of sound
  62.         int length;      // length of sound data
  63.         LPDIRECTSOUNDBUFFER lpdsbuffer; // ptr to sound buffer
  64.         } VOC_FILE, *VOC_FILE_PTR;
  65.  
  66. // PROTOTYPES /////////////////////////////////////////////
  67.  
  68. int Game_Init(void *parms=NULL);
  69. int Game_Shutdown(void *parms=NULL);
  70. int Game_Main(void *parms=NULL);
  71. int Load_VOC(char *voc_file, VOC_FILE_PTR voc_data); 
  72.  
  73. // GLOBALS ////////////////////////////////////////////////
  74.  
  75. HWND main_window_handle = NULL; // save the window handle
  76. HINSTANCE main_instance = NULL; // save the instance
  77. char buffer[80];                // used to print text
  78.  
  79. LPDIRECTSOUND        lpds;           // directsound interface pointer
  80. DSBUFFERDESC        dsbd;           // directsound description
  81. DSCAPS                dscaps;         // directsound caps
  82. HRESULT                dsresult;       // general directsound result
  83. DSBCAPS             dsbcaps;        // directsound buffer caps
  84.  
  85. LPDIRECTSOUNDBUFFER    lpdsbprimary,    // you won't need this normally
  86.                     lpdsbsecondary;  // the sound buffers
  87.  
  88. WAVEFORMATEX        pcmwf;          // generic waveformat structure
  89.  
  90. VOC_FILE            work_voc;       // a working voc file
  91.  
  92. HWND                freq_hwnd,      // window handles for controls
  93.                     volume_hwnd,
  94.                     pan_hwnd;
  95.  
  96. // FUNCTIONS //////////////////////////////////////////////
  97.  
  98. LRESULT CALLBACK WindowProc(HWND hwnd, 
  99.                             UINT msg, 
  100.                             WPARAM wparam, 
  101.                             LPARAM lparam)
  102. {
  103. // this is the main message handler of the system
  104. PAINTSTRUCT    ps;           // used in WM_PAINT
  105. HDC            hdc;       // handle to a device context
  106.  
  107. // what is the message 
  108. switch(msg)
  109.     {    
  110.     case WM_CREATE: 
  111.         {
  112.         // do initialization stuff here
  113.         return(0);
  114.         } break;
  115.  
  116.     case WM_PAINT:
  117.          {
  118.          // start painting
  119.          hdc = BeginPaint(hwnd,&ps);
  120.         
  121.          // first the static text
  122.          // set the color
  123.          SetTextColor(hdc,RGB(0,0,255));
  124.          SetBkColor(hdc,RGB(0,0,0));
  125.          SetBkMode(hdc,OPAQUE);
  126.  
  127.          TextOut(hdc,160-5*7,40-20,"VOLUME        ",strlen("VOLUME        "));
  128.          TextOut(hdc,160-5*13,100-20,"PLAYBACK RATE        ",strlen("PLAYBACK RATE        "));
  129.          TextOut(hdc,160-5*14,160-20,"STEREO PANNING        ",strlen("STEREO PANNING        "));
  130.          
  131.          // end painting
  132.          EndPaint(hwnd,&ps);
  133.          return(0);
  134.         } break;
  135.  
  136. ///////////////////////////////////////////////////////////
  137.  
  138.     case WM_HSCROLL:
  139.     case WM_VSCROLL:
  140.         {
  141.         int nscrollcode    = (int)LOWORD(wparam); // scroll bar value 
  142.         int npos           = (int)HIWORD(wparam); // scroll box position 
  143.         HWND hwndscrollbar = (HWND)lparam;        // handle of scroll bar 
  144.  
  145.         // get teh dc for printing
  146.         hdc = GetDC(hwnd);
  147.         
  148.         // set the color
  149.         SetTextColor(hdc,RGB(0,0,255));
  150.         SetBkColor(hdc,RGB(0,0,0));
  151.         SetBkMode(hdc,OPAQUE);
  152.                 
  153.         // make sure that the scroll bar is being tracked
  154.         if (nscrollcode==SB_THUMBPOSITION || 
  155.             nscrollcode==SB_THUMBTRACK) 
  156.         {
  157.         // what scroll bar sent message
  158.         if (hwndscrollbar==volume_hwnd)
  159.            {
  160.            // re-position scroll bar
  161.            SetScrollPos(volume_hwnd, SB_CTL,npos,TRUE);
  162.            sprintf(buffer,"VOLUME=%d       ",-npos);
  163.            
  164.            // output text
  165.            TextOut(hdc,160-5*7,40-20,buffer,strlen(buffer)); 
  166.  
  167.            // set the volume
  168.            work_voc.lpdsbuffer->SetVolume(-npos);
  169.  
  170.            } // end if
  171.         else
  172.         if (hwndscrollbar==freq_hwnd)
  173.            {
  174.            // re-position scroll bar
  175.            SetScrollPos(freq_hwnd, SB_CTL,npos,TRUE);
  176.            sprintf(buffer,"PLAYBACK RATE=%d      ",npos);
  177.      
  178.            // output text
  179.            TextOut(hdc,160-5*13,100-20,buffer,strlen(buffer));
  180.  
  181.            // set the frequency
  182.            work_voc.lpdsbuffer->SetFrequency(npos);
  183.            } // end if
  184.         // what scroll bar sent message
  185.         else
  186.         if (hwndscrollbar==pan_hwnd)
  187.            {
  188.            // re-position scroll bar
  189.            SetScrollPos(pan_hwnd, SB_CTL,npos,TRUE);
  190.            sprintf(buffer,"STEREO PANNING=%d      ",-(npos-10000));
  191.            
  192.            // output text
  193.            TextOut(hdc,160-5*14,160-20,buffer,strlen(buffer));
  194.  
  195.            // set the stereo panning
  196.            work_voc.lpdsbuffer->SetPan(-(npos-10000));
  197.            } // end if
  198.         
  199.         } // end if
  200.  
  201.         // release the dc
  202.         ReleaseDC(hwnd,hdc);
  203.  
  204.         // message has been processed
  205.         return(0);
  206.  
  207.         } break;
  208.  
  209. ///////////////////////////////////////////////////////////
  210.  
  211.     case WM_DESTROY: 
  212.         {
  213.         // kill the application            
  214.         PostQuitMessage(0);
  215.         return(0);
  216.         } break;
  217.  
  218.     default:break;
  219.  
  220.     } // end switch
  221.  
  222. // process any messages that we didn't take care of 
  223. return (DefWindowProc(hwnd, msg, wparam, lparam));
  224.  
  225. } // end WinProc
  226.  
  227. // WINMAIN ////////////////////////////////////////////////
  228.  
  229. int WINAPI WinMain(    HINSTANCE hinstance,
  230.                     HINSTANCE hprevinstance,
  231.                     LPSTR lpcmdline,
  232.                     int ncmdshow)
  233. {
  234.  
  235. WNDCLASS winclass;    // this will hold the class we create
  236. HWND     hwnd;        // generic window handle
  237. MSG         msg;        // generic message
  238. HDC      hdc;       // generic dc
  239. PAINTSTRUCT ps;     // generic paintstruct
  240.  
  241. // first fill in the window class stucture
  242. winclass.style            = CS_DBLCLKS | CS_OWNDC | 
  243.                           CS_HREDRAW | CS_VREDRAW;
  244. winclass.lpfnWndProc    = WindowProc;
  245. winclass.cbClsExtra        = 0;
  246. winclass.cbWndExtra        = 0;
  247. winclass.hInstance        = hinstance;
  248. winclass.hIcon            = LoadIcon(NULL, IDI_APPLICATION);
  249. winclass.hCursor        = LoadCursor(NULL, IDC_ARROW);
  250. winclass.hbrBackground    = (HBRUSH)GetStockObject(BLACK_BRUSH);
  251. winclass.lpszMenuName    = NULL; 
  252. winclass.lpszClassName    = WINDOW_CLASS_NAME;
  253.  
  254. // register the window class
  255. if (!RegisterClass(&winclass))
  256.     return(0);
  257.  
  258. // create the window, note the use of WS_POPUP
  259. if (!(hwnd = CreateWindow(WINDOW_CLASS_NAME, // class
  260.                           "WinX Game Console - 2001",     // title
  261.                           WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  262.                            0,0,       // x,y
  263.                           WINDOW_WIDTH,  // width
  264.                           WINDOW_HEIGHT, // height
  265.                           NULL,       // handle to parent 
  266.                           NULL,       // handle to menu
  267.                           hinstance,// instance
  268.                           NULL)))    // creation parms
  269. return(0);
  270.  
  271. // save the window handle and instance in a global
  272. main_window_handle = hwnd;
  273. main_instance      = hinstance;
  274.  
  275. // create some scroll controls to change volume, frequency
  276. // and panning
  277.  
  278. // create the volume control scroller
  279. volume_hwnd = CreateWindow("SCROLLBAR", // class
  280.                           "",        // title
  281.                           WS_CHILD | WS_VISIBLE,
  282.                            80,40,        // x,y
  283.                           160,       // width
  284.                           16,      // height
  285.                           hwnd,        // handle to parent 
  286.                           NULL,        // handle to menu
  287.                           hinstance,// instance
  288.                           NULL);    // creation parms
  289.  
  290. // create the frequency control scroller
  291. freq_hwnd = CreateWindow("SCROLLBAR", // class
  292.                           "",        // title
  293.                           WS_CHILD | WS_VISIBLE,
  294.                            80,100,        // x,y
  295.                           160,       // width
  296.                           16,      // height
  297.                           hwnd,        // handle to parent 
  298.                           NULL,        // handle to menu
  299.                           hinstance,// instance
  300.                           NULL);    // creation parms
  301.  
  302. // create the stereo panning control scroller
  303. pan_hwnd = CreateWindow("SCROLLBAR", // class
  304.                           "",        // title
  305.                           WS_CHILD | WS_VISIBLE,
  306.                            80,160,    // x,y
  307.                           160,      // width
  308.                           16,       // height
  309.                           hwnd,        // handle to parent 
  310.                           NULL,        // handle to menu
  311.                           hinstance,// instance
  312.                           NULL);    // creation parms
  313.  
  314.  
  315. // set range and value of each scroll bar
  316. SetScrollRange(volume_hwnd, SB_CTL, 0, 4000,TRUE);
  317. SetScrollPos(volume_hwnd, SB_CTL,0,TRUE);
  318.  
  319. SetScrollRange(freq_hwnd, SB_CTL, 0, 50000,TRUE);
  320. SetScrollPos(freq_hwnd, SB_CTL,11000,TRUE);
  321.  
  322. SetScrollRange(pan_hwnd, SB_CTL, 0, 20000,TRUE);
  323. SetScrollPos(pan_hwnd, SB_CTL,10000,TRUE);
  324.  
  325. // perform all game console specific initialization
  326. // start up the directsound sound
  327. Game_Init();
  328.  
  329. // enter main event loop
  330. while(1)
  331.     {
  332.     if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
  333.         { 
  334.         // test if this is a quit
  335.         if (msg.message == WM_QUIT)
  336.            break;
  337.     
  338.         // translate any accelerator keys
  339.         TranslateMessage(&msg);
  340.  
  341.         // send the message to the window proc
  342.         DispatchMessage(&msg);
  343.         } // end if
  344.     
  345.     // main game processing goes here
  346.     Game_Main();
  347.  
  348.     } // end while
  349.  
  350. // shutdown game and release all resources
  351. Game_Shutdown();
  352.  
  353. // return to Windows like this
  354. return(msg.wParam);
  355.  
  356. } // end WinMain
  357.  
  358. // WINX GAME PROGRAMMING CONSOLE FUNCTIONS ////////////////
  359.  
  360. int Game_Init(void *parms)
  361. {
  362. // this function is where you do all the initialization 
  363. // for your game
  364.  
  365. // create a directsound object
  366. if (DirectSoundCreate(NULL, &lpds, NULL)!=DS_OK )
  367.     return(0);
  368.  
  369. // set cooperation level
  370. if (lpds->SetCooperativeLevel(main_window_handle,DSSCL_NORMAL)!=DS_OK)
  371.     return(0);
  372.  
  373. // load a voc file in
  374. if (Load_VOC("DAVE.VOC",&work_voc))
  375.    {
  376.    // start the voc playing in looping mode
  377.    work_voc.lpdsbuffer->Play(0,0,DSBPLAY_LOOPING);
  378.    } // end if
  379.  
  380. // return success
  381. return(1);
  382.  
  383. } // end Game_Init
  384.  
  385. ///////////////////////////////////////////////////////////
  386.  
  387. int Game_Shutdown(void *parms)
  388. {
  389. // this function is where you shutdown your game and
  390. // release all resources that you allocated
  391.  
  392. // release the sound buffer
  393. if (work_voc.lpdsbuffer)
  394.    work_voc.lpdsbuffer->Release();
  395.  
  396. // release the directsoundobject
  397. if (lpds!=NULL)
  398.    lpds->Release();
  399.  
  400. // return success
  401. return(1);
  402. } // end Game_Shutdown
  403.  
  404. ///////////////////////////////////////////////////////////
  405.  
  406. int Game_Main(void *parms)
  407. {
  408. // this is the workhorse of your game it will be called
  409. // continuously in real-time this is like main() in C
  410. // all the calls for you game go here!
  411.  
  412. // check of user is trying to exit
  413. if (KEY_DOWN(VK_ESCAPE) || KEY_DOWN(VK_SPACE))
  414.     PostMessage(main_window_handle, WM_DESTROY,0,0);
  415.  
  416. // return success
  417. return(1);
  418. } // end Game_Main
  419.  
  420. ///////////////////////////////////////////////////////////
  421.  
  422. int Load_VOC(char *filename,VOC_FILE_PTR voc_data)
  423. {
  424. // this function creates a sound from the send voc_file_ptr
  425. // description and returns a pointer to it
  426.  
  427. int        index,         // looping var
  428.         data_offset,   // working var
  429.         playback_rate, // temp playback rate
  430.         data_length;   // used to hold data length
  431.  
  432. ULONG    bytesread = 0; // actual size of total file
  433. HANDLE    file_handle;   // file handle 
  434. UCHAR    *snd_buffer;   // temporary sound buffer to hold voc data
  435.  
  436. UCHAR    *audio_ptr_1=NULL, // pointer to lock
  437.         *audio_ptr_2=NULL;
  438.  
  439. DWORD    audio_length_1=0,  // lengths to lock
  440.         audio_length_2=0;
  441.  
  442. // load the voc file off disk
  443. if (!(file_handle = CreateFile(filename, 
  444.                         GENERIC_READ,            // access (read-write) mode 
  445.                         0,                        // share mode 
  446.                         NULL,                    // pointer to security descriptor 
  447.                         OPEN_EXISTING,            // how to create 
  448.                         FILE_ATTRIBUTE_NORMAL,    // file attributes 
  449.                         NULL                    // handle to file with attributes to copy  
  450.                         )))
  451.     return(0);
  452.  
  453. // allocate a large enough temporary buffer (hold 50 secs)
  454. snd_buffer = (UCHAR *)malloc(640000);
  455.  
  456. // now read in the data
  457. ReadFile(file_handle, snd_buffer, 640000, &bytesread, NULL);
  458.  
  459. // access all values 
  460. data_offset        = snd_buffer[20];
  461. playback_rate    = (-1000000/(snd_buffer[data_offset+4]-256));
  462. data_length     = ((*(int *)(snd_buffer+data_offset)) >> 8);
  463.  
  464. // set rate and size in data structure
  465. voc_data->sample_rate  = playback_rate;
  466. voc_data->length       = data_length;
  467.  
  468. // close the file
  469. CloseHandle(file_handle);
  470.  
  471. // step three: create the sound buffer and copy voc data into buffer
  472.  
  473. // set up the format data structure
  474. memset(&pcmwf, 0, sizeof(WAVEFORMATEX));
  475.  
  476. pcmwf.wFormatTag    = WAVE_FORMAT_PCM;
  477. pcmwf.nChannels        = 1;
  478. pcmwf.nSamplesPerSec= 11025;
  479. pcmwf.nBlockAlign    = 1;
  480. pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;
  481. pcmwf.wBitsPerSample= 8;
  482. pcmwf.cbSize        = 0;
  483.  
  484. // create the sound buffer
  485. dsbd.dwSize            = sizeof(DSBUFFERDESC);
  486. dsbd.dwFlags        = DSBCAPS_CTRLDEFAULT | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE ;
  487. dsbd.dwBufferBytes    = data_length-NVB_SIZE;
  488. dsbd.lpwfxFormat    = &pcmwf;
  489.  
  490. if (lpds->CreateSoundBuffer(&dsbd,&(voc_data->lpdsbuffer),NULL)!=DS_OK)
  491.     return(0);
  492.  
  493. // copy data into sound buffer
  494. if ((voc_data->lpdsbuffer)->Lock(0,                     
  495.                              data_length-NVB_SIZE,            
  496.                              (void **) &audio_ptr_1, 
  497.                              &audio_length_1,
  498.                              (void **)&audio_ptr_2, 
  499.                              &audio_length_2,
  500.                              DSBLOCK_FROMWRITECURSOR)!=DS_OK)
  501.                              return(0);
  502.  
  503.  
  504. // copy first section of circular buffer
  505. memcpy(audio_ptr_1, snd_buffer+data_offset+NVB_SIZE, audio_length_1);
  506.  
  507. // copy last section of circular buffer
  508. memcpy(audio_ptr_2, (snd_buffer+data_offset+NVB_SIZE+audio_length_1),audio_length_2);
  509.  
  510. // unlock the buffer
  511. if ((voc_data->lpdsbuffer)->Unlock(audio_ptr_1, 
  512.                                     audio_length_1, 
  513.                                     audio_ptr_2, 
  514.                                     audio_length_2)!=DS_OK)
  515.                                     return(0);
  516.  
  517. // release the temp buffer
  518. free(snd_buffer);
  519.  
  520. // return success
  521. return(1);
  522.  
  523. } // end Load_Voc