SHELL.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:77k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*==========================================================================
  2.  *
  3.  *  Copyright (C) 1995-1997 Microsoft Corporation. All Rights Reserved.
  4.  *
  5.  *  File:       shell.c
  6.  *  Content:    Direct Sound show-off.
  7.  *  This app basically uses the direct sound api's and pops up some
  8.  *  controls that the user can play with at runtime to change
  9.  *  the sound frequency, panning, volume, etc.   It has a few
  10.  *  other functions built in.
  11.  *
  12.  *  This app also takes a couple command-line parameters.  The format is:
  13.  *
  14.  * DSShow [/PLAY [/LOOP]] [file] [file] ...
  15.  *
  16.  *    Specifying /PLAY causes any specified files to be played as they're
  17.  * opened.  Adding the /LOOP causes them to loop as well.  /LOOP without
  18.  * /PLAY means nothing.  Everything else is assumed to be one or more file
  19.  * names.  Filenames can be enclosed in quotes.  This also means you can
  20.  * drag and drop files onto the program's icon
  21.  *
  22.  *
  23.  ***************************************************************************/
  24. #define INITGUID
  25. #include <windows.h>
  26. #include <windowsx.h>
  27. #include <commctrl.h>
  28. #include <commdlg.h>
  29. #include <stdio.h>
  30. #include <mmsystem.h>
  31. #include <mmreg.h>
  32. #include <msacm.h>
  33. #include <dsound.h>
  34. #include "wassert.h"
  35. #include "wave.h"
  36. #include "resource.h"
  37. #include "shell.h"
  38. #include "dsenum.h"
  39. // =======================================================================
  40. /* Procedure called when the application is loaded for the first time */
  41. // =======================================================================
  42. BOOL ClassInit( hInstance )
  43. HANDLE hInstance;
  44. {
  45.     WNDCLASS    myClass;
  46.     
  47.     myClass.hCursor             = LoadCursor( NULL, IDC_ARROW );
  48.     myClass.hIcon               = LoadIcon( hInstance, MAKEINTRESOURCE(IDI_ICON3));
  49.     myClass.lpszMenuName        = MAKEINTRESOURCE(IDR_MAINMENU);
  50.     myClass.lpszClassName       = (LPSTR)szAppName;
  51.     myClass.hbrBackground       = (HBRUSH)(COLOR_WINDOW);
  52.     myClass.hInstance           = hInstance;
  53.     myClass.style               = CS_HREDRAW | CS_VREDRAW;
  54.     myClass.lpfnWndProc         = WndProc;
  55.     myClass.cbClsExtra          = 0;
  56.     myClass.cbWndExtra          = 0;
  57.     if (!RegisterClass( &myClass ) )
  58.        return FALSE;
  59.     return TRUE;        /* Initialization succeeded */
  60. }
  61. // =======================================================================
  62. /* This "hook procedure" is called by the common dialog code for certain
  63.  *   events that may occur during the life of our nested dialog structure.
  64.  *  We nest the Explorer style dialog inside our file open dialog so we
  65.  *   can addd a check box for stick buffers.
  66.  */
  67.  // =======================================================================
  68. UINT CALLBACK FileOpenCustomTemplateDlgProc( hDlg, message, wParam, lParam )
  69. HWND hDlg;
  70. UINT message;
  71. WPARAM wParam;
  72. LPARAM lParam;
  73. {
  74.     static LPOPENFILENAME   lpofn = NULL;
  75.     switch( message )
  76.     {
  77.     case WM_INITDIALOG:
  78.         lpofn = (LPOPENFILENAME)lParam;
  79.         /* Set the flag to match the current state of the check box control */
  80.         *((LPBOOL)lpofn->lCustData) = SendDlgItemMessage( hDlg, IDC_FONEST_STICKY,
  81.                                                             BM_GETCHECK, 0, 0 );
  82.         return TRUE;
  83.     case WM_NOTIFY:
  84.         switch(((LPOFNOTIFY)lParam)->hdr.code)
  85.         {
  86.         case CDN_SELCHANGE:
  87.             /* Use this area to process anything that must be updated when the
  88.              * user changes the selection in the Common Dialog Box.
  89.              *   NOTE: Provided only for informational purposes
  90.              */
  91.             return FALSE;
  92.         case CDN_FILEOK:
  93.             /* We can do lots of things in this notification message.  The most
  94.              * important is that we can decide whether the Common Dialog call will
  95.              * go through or whether it will fail.  I decided to handle the checkbox
  96.              * control in this one place versus 4 others... -PRN
  97.              */
  98.             Assert( lpofn != NULL );
  99.             *((LPBOOL)lpofn->lCustData) = SendDlgItemMessage( hDlg, IDC_FONEST_STICKY,
  100.                                                                 BM_GETCHECK, 0, 0 );
  101.             /* Returning zero signifies that we "approve" of the OK command,
  102.              * and allows the common dialog to finish.
  103.              */
  104.             return FALSE;
  105.         }
  106.         /* Let the default dialog do/continue processing */
  107.         return FALSE;
  108.     }
  109.     return FALSE;
  110. }
  111. // =======================================================================
  112. // =======================================================================
  113. int PASCAL WinMain( hInstance, hPrevInstance, lpszCmdLine, cmdShow )
  114. HINSTANCE hInstance, hPrevInstance;
  115. LPSTR lpszCmdLine;
  116. int cmdShow;
  117. {
  118.     MSG   msg;
  119.     HWND  hWnd;
  120.     // We must call this to ensure the common controls are setup for
  121.     // this application
  122.     InitCommonControls();
  123.     if (!hPrevInstance) {
  124. /* Call initialization procedure if this is the first instance */
  125.     if (!ClassInit( hInstance ))
  126.     return FALSE;
  127. }
  128.     
  129.     hWnd = CreateWindow((LPSTR)szAppName,
  130. (LPSTR)szMessage,
  131. WS_OVERLAPPEDWINDOW,
  132. CW_USEDEFAULT,    
  133. CW_USEDEFAULT,    
  134. DX_MINWINDOW,     
  135. DY_MINWINDOW,     
  136. (HWND)NULL,        
  137. (HMENU)NULL,      
  138. (HANDLE)hInstance, 
  139. (LPSTR)NULL        
  140. );
  141.     if (!hWnd) return (int)msg.wParam;
  142.     // Make a long line across the top.
  143.     CreateWindow(
  144. "STATIC", 
  145. "", 
  146. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  147. 0,
  148. 0,
  149. 8000, 
  150. 2,              
  151. hWnd, 
  152. (HMENU)0, 
  153. hInst, 
  154. NULL);
  155.     /* Save instance handle for DialogBox */
  156.     hInst = hInstance;
  157.     
  158.     ShowWindow( hWnd, cmdShow );
  159.     if( lpszCmdLine && *lpszCmdLine )
  160.         if( !ParseCommandLine( lpszCmdLine ))
  161.     goto Exit_WinMain;
  162.     
  163.     /* Polling messages from event queue */
  164.     while (GetMessage((LPMSG)&msg, NULL, 0, 0)) {
  165. TranslateMessage((LPMSG)&msg);
  166. DispatchMessage((LPMSG)&msg);
  167. }
  168. Exit_WinMain:
  169.     DestroyWindow(hWnd);
  170.     UnregisterClass(szAppName, hInstance);
  171.     return (int)msg.wParam;
  172. }
  173. // =======================================================================
  174. /*  This function updates the status window by writing the specified
  175.     string to the window, prepended by a string indicating whether
  176.     the buffer is in hardware or software
  177. */
  178. // =======================================================================
  179. void UpdateStatus(FILEINFO *pFileInfo, DWORD dwStatus)
  180. {
  181.     TCHAR szStatus[200];
  182.     DWORD dwPlay, dwWrite;
  183.     HRESULT hr;
  184.     lstrcpy(szStatus, pFileInfo->fHardware ? szHW : szSW);
  185.     if (dwStatus & DSBSTATUS_BUFFERLOST)
  186.     {
  187.     lstrcat(szStatus, szLost);
  188.     SendMessage(pFileInfo->hWndStatus_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  189.     }
  190.     else if (dwStatus & DSBSTATUS_PLAYING)
  191.     {
  192.     lstrcat(szStatus, szPlaying);
  193.     SendMessage(pFileInfo->hWndStatus_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  194.     }
  195.     else
  196.     {
  197.     lstrcat(szStatus, szStopped);
  198.     SendMessage(pFileInfo->hWndStatus_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  199.     }
  200.     if (pFileInfo->fSticky)
  201. {
  202. lstrcat(szStatus, szSticky);
  203.     SendMessage(pFileInfo->hWndStatus_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  204. }
  205.     hr = IDirectSoundBuffer_GetCurrentPosition(pFileInfo->pDSB, &dwPlay, &dwWrite);
  206.     if (DS_OK == hr) {
  207.     wsprintf(szStatus, szFmtPlayPosition, dwPlay);
  208.     SendMessage(pFileInfo->hWndPlayPosition_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  209.     wsprintf(szStatus, szFmtWritePosition, dwWrite);
  210.     SendMessage(pFileInfo->hWndWritePosition_TXT, WM_SETTEXT, 0, (LPARAM)szStatus);
  211.     }
  212.     return;
  213. }
  214. // =======================================================================
  215. /*  This function updates the main window title to show some
  216.     relevant information about the direct sound object
  217. */
  218. // =======================================================================
  219. void UpdateMainStatus()
  220. {
  221.     DSCAPS  dsc;
  222.     TCHAR   szTitle[200];
  223.     
  224.     // Update main window title with some relevant info
  225.     dsc.dwSize = sizeof(dsc);
  226.     IDirectSound_GetCaps(gpds, &dsc);
  227.     wsprintf(szTitle, "%s : free hw memory = %dKb, free hw buffers = %d",
  228.  szMessage, (dsc.dwFreeHwMemBytes+512)/1024,
  229.  dsc.dwFreeHwMixingAllBuffers);
  230.     SendMessage(hWndMain, WM_SETTEXT, 0, (LPARAM)szTitle);
  231.     return;
  232. }
  233. // =======================================================================
  234. /*  This routine will set up everything needed for the app to run.
  235.     Input:
  236. hWnd                - App main window handle
  237.     Output:
  238. None.
  239. */
  240. // =======================================================================
  241. int AppInit(HWND hWnd)
  242. {
  243.     UINT            cT;
  244.     DSBUFFERDESC    dsbd;
  245.     BOOL     fUseGuid;
  246.     HRESULT         hr;
  247.     DWORD           dw;
  248.     // Set up the global window handle.
  249.     hWndMain = hWnd;
  250.     // Set up the global File...Open dialog's start directory
  251.     GetMediaStartPath();
  252.     // Set up the file info header
  253.     FileInfoFirst.pNext = NULL;
  254.     FileInfoFirst.pwfx = NULL;
  255.     FileInfoFirst.cox = COX_STARTCONTROL;
  256.     FileInfoFirst.coy = COY_STARTCONTROL;
  257.     // Clear the coordinate buffer.  Used to find the next available
  258.     // position to use for a new control.  -1 is the invalid value.
  259.     for (cT=0; cT<MAXCONTROLS; cT++) rgfcoxAvail[cT] = FALSE;
  260.     // Setup the timer...
  261.     if ((dwTimer = SetTimer(hWnd, 1, TIMERPERIOD, NULL)) == 0) 
  262. {
  263. MessageBox(hWnd, "Cannot allocate timer, aborting", "DirectSound Demo", MB_OK|MB_ICONSTOP);
  264. return -1;
  265.     }
  266.     // Now set up all the direct sound stuff...
  267.     // Get the largest waveformatex structure.
  268.     if (MMSYSERR_NOERROR != acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &dw))
  269.     {
  270. MessageBox(hWnd, "ACM Metrics failed, aborting", "DirectSound Demo",
  271.    MB_OK|MB_ICONSTOP);
  272. return -1;
  273.     }
  274.     // Setup the format, frequency, volume, etc.
  275.     if ((FileInfoFirst.pwfx = GlobalAllocPtr(GPTR, dw)) == NULL)
  276.     {
  277. MessageBox(hWnd, "Out of Memory", "DirectSound Demo",
  278.    MB_OK|MB_ICONSTOP);
  279. return -1;
  280.     }
  281.     FileInfoFirst.pwfx->wFormatTag = WAVE_FORMAT_PCM;
  282.     FileInfoFirst.pwfx->nChannels = 2;
  283.     FileInfoFirst.pwfx->nSamplesPerSec = 22050;
  284.     FileInfoFirst.pwfx->nAvgBytesPerSec = 22050*2*2;
  285.     FileInfoFirst.pwfx->nBlockAlign = 4;
  286.     FileInfoFirst.pwfx->wBitsPerSample = 16;
  287.     FileInfoFirst.pwfx->cbSize = 0;
  288.     
  289. #ifdef STARTEIGHTBITS
  290.     FileInfoFirst.pwfx->wFormatTag = WAVE_FORMAT_PCM;
  291.     FileInfoFirst.pwfx->nChannels = 2;
  292.     FileInfoFirst.pwfx->nSamplesPerSec = 22050;
  293.     FileInfoFirst.pwfx->nAvgBytesPerSec = 22050*1*2;
  294.     FileInfoFirst.pwfx->nBlockAlign = 2;
  295.     FileInfoFirst.pwfx->wBitsPerSample = 8;
  296.     FileInfoFirst.pwfx->cbSize = 0;
  297. #endif
  298. #ifdef STARTMONO    
  299.     FileInfoFirst.pwfx->wFormatTag = WAVE_FORMAT_PCM;
  300.     FileInfoFirst.pwfx->nChannels = 1;
  301.     FileInfoFirst.pwfx->nSamplesPerSec = 22050;
  302.     FileInfoFirst.pwfx->nAvgBytesPerSec = 22050*1*2;
  303.     FileInfoFirst.pwfx->nBlockAlign = 2;
  304.     FileInfoFirst.pwfx->wBitsPerSample = 16;
  305.     FileInfoFirst.pwfx->cbSize = 0;
  306. #endif
  307.     
  308.     // Optionally enumerate DSOUND devices and allow the user to pick one...
  309.     if (!SUCCEEDED(CoInitialize(NULL))) {
  310. MessageBox(hWnd, "Failed to initialize COM library", "DirectSound Demo", MB_OK | MB_ICONSTOP);
  311. return -1;
  312.     }
  313.     
  314.     fEnumDrivers = (BOOL)GetProfileInt( "DSSHOW", "EnumDrivers", FALSE );
  315. fUseGuid = (fEnumDrivers && !DoDSoundEnumerate(&guID));
  316. // Create the direct sound object.
  317.     hr = CoCreateInstance(&CLSID_DirectSound, NULL, CLSCTX_INPROC_SERVER,
  318.   &IID_IDirectSound, &gpds);
  319.     if (SUCCEEDED(hr) && (NULL != gpds))
  320. {
  321. hr = IDirectSound_Initialize(gpds, fUseGuid ? &guID : NULL);
  322. if (SUCCEEDED(hr)) 
  323. {
  324. // Note we need to set the level to be priority to set the
  325. // format of the primary buffer
  326. hr = IDirectSound_SetCooperativeLevel(gpds, hWndMain, DSSCL_PRIORITY);
  327. if (SUCCEEDED(hr)) 
  328. {
  329. // Set up the primary direct sound buffer.
  330. ZeroMemory(&dsbd, sizeof(dsbd));
  331. dsbd.dwSize = sizeof(dsbd);
  332. dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
  333.     
  334. hr = IDirectSound_CreateSoundBuffer(gpds, &dsbd, &(FileInfoFirst.pDSB), NULL);
  335. if (SUCCEEDED(hr)) 
  336. {
  337. hr = IDirectSoundBuffer_Play(FileInfoFirst.pDSB, 0, 0, DSBPLAY_LOOPING);
  338. if (SUCCEEDED(hr)) 
  339. {
  340. UpdateMainStatus();
  341. else 
  342. {
  343. MessageBox(hWnd, "Cannot play primary buffer","DirectSound Demo", MB_OK|MB_ICONSTOP);
  344. IDirectSoundBuffer_Release(FileInfoFirst.pDSB);
  345. FileInfoFirst.pDSB = NULL;
  346.     }
  347. else 
  348. {
  349. MessageBox(hWnd, "Cannot create primary buffer","DirectSound Demo", MB_OK|MB_ICONSTOP);
  350. }
  351.     } 
  352. else 
  353. {
  354. MessageBox(hWnd, "DirectSound SetCooperativeLevel failed","DirectSound Demo", MB_OK|MB_ICONSTOP);
  355.     }
  356. } //initialize
  357. else 
  358. {
  359.     MessageBox(hWnd, "Failed to Initialize DirectSound object", "DirectSound Demo", MB_OK | MB_ICONSTOP);
  360. }
  361. if (!SUCCEEDED(hr)) 
  362. {
  363.     IDirectSound_Release(gpds);
  364.     gpds = NULL;
  365. }
  366.  } 
  367. else 
  368. {
  369. MessageBox(hWnd, "Failed to create DirectSound COM object",
  370.    "DirectSound Demo", MB_OK | MB_ICONSTOP);
  371. }
  372. if (SUCCEEDED(hr)) 
  373. {
  374. return 0;
  375. else 
  376. {
  377. CoUninitialize();
  378. return -1;
  379. }
  380. }
  381. // =======================================================================
  382. /*  This will destroy all the created objects, allocated memory, etc.  Must be called
  383.     before termination of app.
  384.     Input:
  385. hWnd                - Window handle of main window
  386.     Output:
  387. None.
  388. */
  389. // =======================================================================
  390. void AppDestroy( HWND hWnd )
  391. {
  392.     HRESULT     hr = 0;
  393.     if (dwTimer != 0)
  394.     {
  395. KillTimer(hWnd, dwTimer);
  396. dwTimer = 0;
  397.     }
  398.     StopAllDSounds(hWnd, &FileInfoFirst);
  399.     FreeAllList(hWnd, &FileInfoFirst);
  400.     // Destroy the direct sound buffer.
  401.     if(FileInfoFirst.pDSB != NULL) 
  402.     {
  403. IDirectSoundBuffer_Stop(FileInfoFirst.pDSB);
  404. IDirectSoundBuffer_Release(FileInfoFirst.pDSB);
  405. FileInfoFirst.pDSB = NULL;
  406.     }
  407.     // Destroy the direct sound object.
  408.     if (gpds != NULL)
  409.     {
  410. IDirectSound_Release(gpds);
  411. gpds = NULL;
  412. CoUninitialize();
  413.     }
  414.     if (FileInfoFirst.pwfx != NULL)
  415.     {
  416. GlobalFreePtr(FileInfoFirst.pwfx);
  417. FileInfoFirst.pwfx = NULL;
  418.     }
  419.     if (FileInfoFirst.pbData != NULL)
  420.     {
  421. GlobalFreePtr(FileInfoFirst.pbData);
  422. FileInfoFirst.pbData = NULL;
  423.     }
  424.     WriteProfileString( "DSSHOW", "EnumDrivers", fEnumDrivers ? "1" : "0" );
  425. }
  426. // =======================================================================
  427. /* Procedures which make up the window class. */
  428. // =======================================================================
  429. long FAR PASCAL WndProc( hWnd, message, wParam, lParam )
  430. HWND hWnd;
  431. unsigned message;
  432. WPARAM wParam;
  433. LPARAM lParam;
  434. {
  435.     switch (message)
  436. {
  437. case WM_CREATE:
  438.     if (AppInit(hWnd)) return (-1);
  439.     break;
  440. case WM_TIMER:  
  441.     if (!UIMainWindowTimerHandler(hWnd, wParam, lParam))
  442. return(DefWindowProc(hWnd, message, wParam, lParam));                           
  443.     break;
  444.     
  445.     
  446. case WM_HSCROLL:
  447.     if (!UIMainWindowHSBHandler(hWnd, wParam, lParam))
  448. return(DefWindowProc(hWnd, message, wParam, lParam));
  449.     
  450.     break;
  451. case WM_VSCROLL:
  452.     if (!UIMainWindowVSBHandler(hWnd, wParam, lParam))
  453. return(DefWindowProc(hWnd, message, wParam, lParam));
  454.     break;
  455.     
  456. case WM_INITMENU:
  457. if((HMENU)wParam != GetMenu( hWnd ))
  458.     break;
  459. CheckMenuItem((HMENU)wParam, IDPD_ENUMDRIVERS,
  460. fEnumDrivers ? MF_CHECKED : MF_UNCHECKED );
  461. break;
  462. case WM_COMMAND:
  463.     if (!UIMainWindowCMDHandler(hWnd, wParam, lParam))
  464. return(DefWindowProc(hWnd, message, wParam, lParam));
  465.     break;
  466.     
  467.     break;
  468. /*case WM_PAINT:
  469.     {           
  470.     
  471.     break;
  472.     }*/
  473. case WM_DESTROY:
  474.     AppDestroy(hWnd);
  475.     PostQuitMessage( 0 );
  476.     break;
  477. default:
  478.     return DefWindowProc( hWnd, message, wParam, lParam );
  479.     break;
  480.     
  481. }
  482.     
  483.     return(0L);
  484. }
  485. // =======================================================================
  486. /*  This routine will pop up the open file dialog and open a file, and make any internal
  487.     arrangements so we know the file is loaded.
  488.     Input:
  489. hWnd            -   Handle of parent window.
  490.     Output:
  491. None.
  492. */
  493. // =======================================================================
  494. void PD_FileOpen( HWND hWnd )
  495. {
  496.     char            szFileName[MAX_PATH];
  497.     UINT            cSamples;
  498.     FILEINFO        *pFileInfo                  = NULL;
  499.     int             nFileName;
  500.     BOOL            fSticky;
  501.     if (GetNumControls(&FileInfoFirst) >= MAXCONTROLS)
  502.     {
  503.     MessageBox(hWnd, "No more controls allowed",
  504.    "Hold on a sec...", MB_OK);
  505.     return;
  506.     }
  507.     // Open the file, and check its format, etc.
  508.     if (OpenFileDialog(hWnd, szFileName, &nFileName, &fSticky))
  509.     {
  510.     // Allocate the memory for the structure.
  511.     if ((pFileInfo = GlobalAllocPtr(GPTR, sizeof(FILEINFO))) == NULL)
  512.     {
  513. MessageBox(hWnd, "Cannot add this file",
  514.        "Out of Memory", MB_OK|MB_ICONSTOP);
  515. goto ERROR_DONE_ROUTINE;
  516.     }
  517.     pFileInfo->pbData   = NULL;
  518.     pFileInfo->pwfx     = NULL;
  519.     pFileInfo->pDSB     = NULL;
  520.     pFileInfo->fSticky  = fSticky;
  521.     strcpy(pFileInfo->szFileName, szFileName);
  522.     
  523.     if (WaveLoadFile(szFileName, &pFileInfo->cbSize, 
  524.     &cSamples, &pFileInfo->pwfx, &pFileInfo->pbData) != 0)
  525.     {
  526. MessageBox(hWnd, "Bad wave file or file too big to fit in memory",
  527. "Cannot load wave", MB_OK|MB_ICONSTOP);
  528. goto ERROR_DONE_ROUTINE;
  529.     }
  530.     GetNextControlCoords(&FileInfoFirst,
  531.      &pFileInfo->cox, &pFileInfo->coy);
  532.     if (NewDirectSoundBuffer(pFileInfo) != 0)
  533.     {
  534. MessageBox(hWnd, "Cannot create new buffer",
  535.        "Direct Sound Error", MB_OK|MB_ICONSTOP);
  536. goto ERROR_DONE_ROUTINE;
  537.     }
  538.     Assert(pFileInfo->pbData != NULL);
  539.     // If we fail after this, make sure to update the list!!!
  540.     if (AddToList(&FileInfoFirst, pFileInfo) != 0)
  541.     {
  542. MessageBox(hWnd, "Cannot add file to list",
  543.    "Out of Memory", MB_OK|MB_ICONSTOP);
  544. goto ERROR_DONE_ROUTINE;
  545.     }
  546.     pFileInfo->nFileName = nFileName;
  547.     CreateControl(hWnd, pFileInfo, pFileInfo->pwfx->nSamplesPerSec,
  548.       (MAXPAN_TB-MINPAN_TB)/2, MINVOL_TB );
  549.     ChangeOutputVol(pFileInfo);
  550.     ChangeOutputFreq(pFileInfo);
  551.     ChangeOutputPan(pFileInfo);
  552.     UpdateMainStatus();
  553.     }
  554.     goto DONE_ROUTINE;
  555.    
  556. ERROR_DONE_ROUTINE:
  557.     if (pFileInfo != NULL)
  558.     {
  559.     ReleaseDirectSoundBuffer(pFileInfo);
  560.     if (pFileInfo->pwfx != NULL)
  561.     {
  562. GlobalFreePtr(pFileInfo->pwfx);
  563.     
  564.     }
  565.     if (pFileInfo->pbData != NULL)
  566.     {
  567. GlobalFreePtr(pFileInfo->pbData);           
  568.     }
  569.     GlobalFreePtr(pFileInfo);
  570.     pFileInfo = NULL;
  571.     }
  572. DONE_ROUTINE:
  573.     return;
  574. }
  575. // =======================================================================
  576. /*  This routine will initialize a new direct sound buffer,
  577.     set the data in the buffer, 
  578.     set the rate, format, etc...
  579.     Input:
  580. pFileInfo   -   Pointer to file info with all
  581. nessecary info filled, 
  582. like pbData, cbData, etc...
  583.     Output:
  584. 0 if successful, else the error code.
  585. */
  586. // =======================================================================
  587. int NewDirectSoundBuffer(FILEINFO *pFileInfo)
  588. {
  589.     DSBUFFERDESC        dsbd;
  590.     DSBCAPS         dsbc;
  591.     HRESULT         hr;
  592.     BYTE            *pbData         = NULL;
  593.     BYTE            *pbData2        = NULL;
  594.     DWORD           dwLength;
  595.     DWORD           dwLength2;
  596.     // Set up the direct sound buffer. 
  597.     memset(&dsbd, 0, sizeof(DSBUFFERDESC));
  598.     dsbd.dwSize                 = sizeof(DSBUFFERDESC);
  599.     dsbd.dwFlags                = 0;
  600.     dsbd.dwFlags                |= DSBCAPS_STATIC;
  601.     // Use new GetCurrentPosition() accuracy (DirectX 2 feature)
  602.     dsbd.dwFlags                |= DSBCAPS_CTRLDEFAULT | DSBCAPS_GETCURRENTPOSITION2;
  603.     if (pFileInfo->fSticky)
  604.         dsbd.dwFlags |= DSBCAPS_STICKYFOCUS;
  605.     dsbd.dwBufferBytes               = pFileInfo->cbSize;
  606.     dsbd.lpwfxFormat            = pFileInfo->pwfx;
  607.     if ((hr = gpds->lpVtbl->CreateSoundBuffer(gpds,
  608.   &dsbd,
  609.   &(pFileInfo->pDSB),
  610.   NULL )) != 0)
  611. {
  612. goto ERROR_IN_ROUTINE;
  613. }
  614.     // Ok, lock the sucker down, and copy the memory to it.
  615.     if ((hr = pFileInfo->pDSB->lpVtbl->Lock(pFileInfo->pDSB,
  616. 0,
  617. pFileInfo->cbSize,
  618. &pbData,
  619. &dwLength,
  620. &pbData2,
  621. &dwLength2,
  622.     0L)) != 0)
  623.     {
  624.     goto ERROR_IN_ROUTINE;
  625.     }
  626.     Assert(pbData != NULL);
  627.     memcpy(pbData, pFileInfo->pbData, pFileInfo->cbSize);
  628.     // Ok, now unlock the buffer, we don't need it anymore.
  629.     if ((hr = pFileInfo->pDSB->lpVtbl->Unlock(pFileInfo->pDSB,
  630.       pbData, pFileInfo->cbSize,
  631.       NULL, 0)) != 0)
  632.     {
  633.     goto ERROR_IN_ROUTINE;
  634.     }
  635.     pbData = NULL;
  636.     if ((hr = pFileInfo->pDSB->lpVtbl->SetVolume(pFileInfo->pDSB,
  637.     MAXVOL_VAL)) != 0)
  638.     {
  639.     goto ERROR_IN_ROUTINE;
  640.     }
  641.     if ((hr = pFileInfo->pDSB->lpVtbl->SetPan(pFileInfo->pDSB,
  642.     MIDPAN_VAL)) != 0)
  643.     {
  644.     goto ERROR_IN_ROUTINE;
  645.     }
  646.     dsbc.dwSize = sizeof(dsbc);
  647.     if (hr = IDirectSoundBuffer_GetCaps(pFileInfo->pDSB, &dsbc))
  648.     {
  649.     goto ERROR_IN_ROUTINE;
  650.     }
  651.     if (dsbc.dwFlags & DSBCAPS_LOCHARDWARE) {
  652.     pFileInfo->fHardware = TRUE;
  653.     } else {
  654.     pFileInfo->fHardware = FALSE;
  655.     }
  656.     goto DONE_ROUTINE;
  657. ERROR_IN_ROUTINE:
  658.     if (pbData != NULL)
  659.     {
  660.     hr = pFileInfo->pDSB->lpVtbl->Unlock(pFileInfo->pDSB, pbData,
  661. pFileInfo->cbSize, NULL, 0);
  662.     pbData = NULL;
  663.     }
  664.     if (pFileInfo->pDSB != NULL)
  665.     {
  666.     pFileInfo->pDSB->lpVtbl->Release(pFileInfo->pDSB);
  667.     pFileInfo->pDSB = NULL;
  668.     }
  669.     
  670. DONE_ROUTINE:
  671.     return(hr); 
  672. }
  673. // =======================================================================
  674. /*  This routine will release a direct sound buffer,
  675.     freeing up memory, resources, 
  676.     whatever.
  677.     Input:
  678. pFileInfo   -   Pointer to the file info,
  679. with the proper stuff set.
  680.     Output: 
  681. 0 if successful, else the error code.
  682. */
  683. // =======================================================================
  684. int ReleaseDirectSoundBuffer( FILEINFO *pFileInfo )
  685. {
  686.     if (pFileInfo->pDSB != NULL)
  687.     {
  688.     pFileInfo->pDSB->lpVtbl->Release(pFileInfo->pDSB);
  689.     pFileInfo->pDSB = NULL; 
  690.     }
  691.     return(0);
  692. }
  693. // =======================================================================
  694. /*  This routine will find the next x and y coordinates to
  695.     write the control to.
  696.     The rgfcoxAvail is an array of booleans.
  697.     If false, then the index can be 
  698.     used as an x coordinate.
  699.     Input:
  700. pFileInfoHead - Header of the linked list.
  701. pcox, pcoy    - Filled upon return with next
  702. coordinates to use.
  703.     Output:
  704. Only pcox and pcoy change.
  705. */
  706. // =======================================================================
  707. void GetNextControlCoords(                     
  708.     FILEINFO    *pFileInfoHead, 
  709.     int         *pcox, 
  710.     int         *pcoy
  711.     )
  712. {
  713.     UINT            cT;
  714.     for (cT=0; cT<MAXCONTROLS; cT++)
  715.     {
  716.     if (rgfcoxAvail[cT] == FALSE)
  717.     {
  718. rgfcoxAvail[cT] = TRUE;
  719. break;
  720.     }
  721.     
  722.     }
  723.     if (cT == MAXCONTROLS)
  724.     {
  725.     Assert(FALSE);
  726.     // Couldn't find a place to put control, shouldn't happen though.
  727.     cT = 666;       // Well, at least put it off screen.
  728.     }
  729.     *pcox = cT*DX_CONTROLSPACING+COX_STARTCONTROL;      //Offsetting the text from the border
  730.     *pcoy = COY_STARTCONTROL;
  731.     
  732. }
  733. // =======================================================================
  734. /*  CreateControl
  735.     This will create the control used for the window, actually it is a
  736.     bundle of controls put together.  I was thinking of a good way to
  737.     figure out id codes for the controls but found no good way except a
  738.     "funny" way...I'm going to use the x coordinate of the control as the
  739.     id for the first control, then id+1 for the second control.  Since
  740.     all the controls have different x coordinates, this is fine, as long
  741.     as the # of windows in the control is not more than the spacing of
  742.     the controls.
  743.     Input:
  744. hWnd                -   Parent Window.
  745. pFileInfo           -   Pointer to FileInfo structure with the cox and coy filled.
  746. dwFreq, dwPan, dwVol-   Default track bar values.
  747.     Output:
  748. 0 if successful, else the error code.
  749. */
  750. // =======================================================================
  751. int CreateControl(HWND hWnd, FILEINFO *pFileInfo, DWORD dwFreq,DWORD dwPan, DWORD dwVol)
  752. {
  753.     int cox, coy;
  754.     int     coxOld, coyOld;
  755.     int     nError = 0;
  756.     DWORD idBase;
  757.     SIZE    Size;       
  758.     HDC     hDC = NULL;
  759. DWORD dwMinFreq, dwMaxFreq;
  760.     /* Figure out the values of dwPan and dwVol that the track bars like */
  761.     idBase = pFileInfo->cox;
  762.     Assert(pFileInfo != NULL);
  763.     cox = pFileInfo->cox+DX_TEXTSPACING;
  764.     coy = pFileInfo->coy+DY_TEXTSPACING;        //We may have to shift this
  765.     coxOld = cox;
  766.     coyOld = coy;
  767. coy -= 8;                       //We must adjust to fit the text in the border
  768.     if ((hDC = GetDC(hWnd)) == NULL)
  769. {
  770. nError = -1;
  771. goto DONE_ROUTINE;
  772. }
  773.     if (!GetTextExtentPoint32(hDC, pFileInfo->szFileName+pFileInfo->nFileName, strlen(pFileInfo->szFileName+pFileInfo->nFileName), &Size))
  774. {
  775. nError = -1;
  776. goto DONE_ROUTINE;
  777. }
  778.     //Creates the Filename window
  779.     if ((pFileInfo->hWndFileName_TXT = CreateWindow(
  780. "STATIC", 
  781. pFileInfo->szFileName+pFileInfo->nFileName, 
  782. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  783. cox,
  784. coy,                                                                    
  785. DX_FILENAME_TXT,                                                                        
  786. Size.cy,              
  787. hWnd, 
  788. (HMENU)0, 
  789. hInst, 
  790. NULL)) == NULL)
  791. {
  792. nError = -1;
  793. goto DONE_ROUTINE;
  794. }   
  795. //Create line under Filename            
  796.     cox += DX_LOOPEDSPACING;
  797.     coy += Size.cy + DY_TEXTSPACING + DY_LOOPEDSPACING;
  798.     if ((pFileInfo->hWndFileName_EDGE = CreateWindow(
  799. "STATIC", 
  800. "", 
  801. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  802. cox,
  803. coy - (DY_LOOPEDSPACING+DY_TEXTSPACING)/2,
  804. DX_LINEEDGE, 
  805. DY_LINEEDGE,                
  806. hWnd, 
  807. (HMENU)0, 
  808. hInst, 
  809. NULL)) == NULL)
  810. {
  811. nError = -1;
  812. goto DONE_ROUTINE;
  813. }   
  814.     // Now create status if required.
  815.     
  816.     #ifdef SHOWSTATUS   
  817.     if (!GetTextExtentPoint32(hDC, szPlaying, strlen(szPlaying), &Size))
  818. {
  819. nError = -1;
  820. goto DONE_ROUTINE;
  821. }
  822.     //Creates Status Window
  823.     if ((pFileInfo->hWndStatus_TXT = CreateWindow(
  824. "STATIC", 
  825. "",
  826. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  827. cox,
  828. coy,
  829. DX_STATUS_TXT, 
  830. Size.cy, // + DY_TEXTSPACING,               
  831. hWnd, 
  832. (HMENU)0, 
  833. hInst, 
  834. NULL)) == NULL)
  835. {
  836. nError = -1;
  837. goto DONE_ROUTINE;
  838. }   
  839.     cox += DX_LOOPEDSPACING;
  840.     coy += Size.cy + DY_TEXTSPACING + DY_LOOPEDSPACING;
  841.     //Create line under Status
  842.     if ((pFileInfo->hWndStatus_EDGE = CreateWindow(
  843. "STATIC", 
  844. "", 
  845. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  846. cox,
  847. coy - (DY_LOOPEDSPACING+DY_TEXTSPACING)/2,
  848. DX_LINEEDGE, 
  849. DY_LINEEDGE,                
  850. hWnd, 
  851. (HMENU)0, 
  852. hInst, 
  853. NULL)) == NULL)
  854. {
  855. nError = -1;
  856. goto DONE_ROUTINE;
  857. }
  858.     //Creates PlayPos Window
  859.     if ((pFileInfo->hWndPlayPosition_TXT = CreateWindow(
  860. "STATIC", "",
  861. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
  862. cox, 
  863. coy,
  864. DX_STATUS_TXT, 
  865. Size.cy,
  866. hWnd, 
  867. NULL, 
  868. hInst, 
  869. NULL)) == NULL)
  870.     {
  871. nError = -1;
  872. goto DONE_ROUTINE;
  873.     }
  874.     cox += DX_LOOPEDSPACING;
  875.     coy += Size.cy + DY_TEXTSPACING + DY_LOOPEDSPACING; //Create line under PlayPos
  876.     
  877.     if ((pFileInfo->hWndPlayPosition_EDGE = CreateWindow(
  878. "STATIC", "", 
  879. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  880. cox, 
  881. coy - (DY_LOOPEDSPACING+DY_TEXTSPACING)/2,
  882. DX_LINEEDGE, 
  883. DY_LINEEDGE,               
  884. hWnd, 
  885. NULL, 
  886. hInst, 
  887. NULL)) == NULL)
  888.     {
  889. nError = -1;
  890. goto DONE_ROUTINE;
  891.     }
  892.     
  893.     //Creates WritePos Window
  894.     if ((pFileInfo->hWndWritePosition_TXT = CreateWindow(
  895. "STATIC", "",
  896. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP,
  897. cox, 
  898. coy,
  899. DX_STATUS_TXT, 
  900. Size.cy,
  901. hWnd, 
  902. NULL, 
  903. hInst, 
  904. NULL)) == NULL)
  905.     {
  906. nError = -1;
  907. goto DONE_ROUTINE;
  908.     }
  909.     cox += DX_LOOPEDSPACING;
  910.     coy += Size.cy + DY_TEXTSPACING + DY_LOOPEDSPACING;
  911.     
  912.     //Create line under WritePos
  913.     if ((pFileInfo->hWndWritePosition_EDGE = CreateWindow(
  914. "STATIC", "", 
  915. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  916. cox, 
  917. coy - (DY_LOOPEDSPACING+DY_TEXTSPACING)/2,
  918. DX_LINEEDGE,
  919. DY_LINEEDGE,               
  920. hWnd,
  921. NULL, 
  922. hInst, 
  923. NULL)) == NULL)
  924.     {
  925. nError = -1;
  926. goto DONE_ROUTINE;
  927.     }
  928.     
  929.     #endif      
  930.     //Set up the Freq Text
  931.     if (!GetTextExtentPoint32(hDC, szFreq, strlen(szFreq), &Size))
  932. {
  933. nError = -1;
  934. goto DONE_ROUTINE;
  935. }
  936.     // Make the frequency text there.
  937.     if ((pFileInfo->hWndFreq_TXT = CreateWindow(
  938. "STATIC", 
  939. szFreq, 
  940. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  941. cox,
  942. coy,
  943. DX_FREQ_TXT, 
  944. Size.cy,                
  945. hWnd, 
  946. (HMENU)0, 
  947. hInst, 
  948. NULL)) == NULL)
  949. {
  950. nError = -1;
  951. goto DONE_ROUTINE;
  952. }   
  953.     coy += Size.cy;
  954.     // Make the frequency trackbar.
  955.     if ((pFileInfo->hWndFreq_TB = CreateWindow(
  956. TRACKBAR_CLASS, 
  957. "", 
  958. WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_BOTH, 
  959. cox,
  960. coy,
  961. DX_FREQ_TB, 
  962. DY_FREQ_TB,             
  963. hWnd, 
  964. (HMENU)(idBase+idFreqTB), 
  965. hInst, 
  966. NULL)) == NULL)
  967. {
  968. nError = -1;
  969. goto DONE_ROUTINE;
  970. }   
  971. // get the min and max range that the sound card supports.
  972. // If the buffer is in hardware query the card, else use
  973. // our ifdef'd values.
  974. if (pFileInfo->fHardware)
  975. {
  976. DSCAPS dsc;
  977. memset(&dsc, 0, sizeof(DSCAPS));
  978. dsc.dwSize = sizeof(DSCAPS);
  979.     nError = IDirectSound_GetCaps(gpds, &dsc);
  980. Assert(nError == DS_OK);
  981. dwMinFreq = dsc.dwMinSecondarySampleRate;
  982. dwMaxFreq = dsc.dwMaxSecondarySampleRate;
  983. }
  984. else
  985. {
  986. dwMinFreq = DSBFREQUENCY_MIN;
  987. dwMaxFreq = DSBFREQUENCY_MAX;
  988. }
  989. SendMessage(pFileInfo->hWndFreq_TB, TBM_SETRANGEMIN, FALSE, dwMinFreq / FREQFACTOR );
  990. SendMessage(pFileInfo->hWndFreq_TB, TBM_SETRANGEMAX, FALSE, dwMaxFreq / FREQFACTOR );
  991.     SendMessage(pFileInfo->hWndFreq_TB, TBM_SETPAGESIZE, 0, FREQPAGE );
  992.     SendMessage(pFileInfo->hWndFreq_TB, TBM_SETPOS, TRUE, (dwFreq + FREQADD)/FREQFACTOR);
  993.     pFileInfo->dwFreq = dwFreq;
  994.     coy += DY_FREQ_TB+DY_PANSPACING;    
  995.     if ((pFileInfo->hWndFreq_EDGE = CreateWindow(
  996. "STATIC", 
  997. "", 
  998. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  999. cox,
  1000. coy - (DY_PANSPACING+DY_TEXTSPACING)/2,
  1001. DX_LINEEDGE, 
  1002. DY_LINEEDGE,                
  1003. hWnd, 
  1004. (HMENU)0, 
  1005. hInst, 
  1006. NULL)) == NULL)
  1007. {
  1008. nError = -1;
  1009. goto DONE_ROUTINE;
  1010. }   
  1011.     //Adjusts the relative position of the Text    
  1012.     coy -= (((DY_PANSPACING+DY_TEXTSPACING)/2)-((DY_LOOPEDSPACING+DY_TEXTSPACING)/2));
  1013.     if (!GetTextExtentPoint32(hDC, szPan, strlen(szPan), &Size))
  1014. {
  1015. nError = -1;
  1016. goto DONE_ROUTINE;
  1017. }
  1018.     // Make the pan text there.
  1019.     if ((pFileInfo->hWndPan_TXT = CreateWindow(
  1020. "STATIC", 
  1021. szPan, 
  1022. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  1023. cox,
  1024. coy,
  1025. DX_PAN_TXT, 
  1026. Size.cy,                
  1027. hWnd, 
  1028. (HMENU)0, 
  1029. hInst, 
  1030. NULL)) == NULL)
  1031. {
  1032. nError = -1;
  1033. goto DONE_ROUTINE;
  1034. }   
  1035.     coy += Size.cy;
  1036.     // Make the pan trackbar.
  1037.     if ((pFileInfo->hWndPan_TB = CreateWindow(
  1038. TRACKBAR_CLASS, 
  1039. "", 
  1040. WS_CHILD | WS_VISIBLE | TBS_HORZ | TBS_BOTH, 
  1041. cox,
  1042. coy,
  1043. DX_PAN_TB, 
  1044. DY_PAN_TB,              
  1045. hWnd, 
  1046. (HMENU)(idBase+idPanTB), 
  1047. hInst, 
  1048. NULL)) == NULL)
  1049. {
  1050. nError = -1;
  1051. goto DONE_ROUTINE;
  1052. }   
  1053.     SendMessage(pFileInfo->hWndPan_TB, TBM_SETRANGE, FALSE, MAKELONG(MINPAN_TB, MAXPAN_TB)); 
  1054.     SendMessage(pFileInfo->hWndPan_TB, TBM_SETPOS, TRUE, dwPan);
  1055. SendMessage(pFileInfo->hWndPan_TB, TBM_SETPAGESIZE, 0, PANPAGE );
  1056.     pFileInfo->dwPan = dwPan;
  1057.     coy += DY_PAN_TB + DY_VOLSPACING;
  1058.     if ((pFileInfo->hWndPan_EDGE = CreateWindow(
  1059. "STATIC", 
  1060. "", 
  1061. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  1062. cox,
  1063. coy - (DY_VOLSPACING+DY_TEXTSPACING)/2,
  1064. DX_LINEEDGE, 
  1065. DY_LINEEDGE,                
  1066. hWnd, 
  1067. (HMENU)0, 
  1068. hInst, 
  1069. NULL)) == NULL)
  1070. {
  1071. nError = -1;
  1072. goto DONE_ROUTINE;
  1073. }   
  1074.     //Adjusts the relative position of the Text
  1075.     coy -= (((DY_PANSPACING+DY_TEXTSPACING)/2)-((DY_LOOPEDSPACING+DY_TEXTSPACING)/2));
  1076.     if (!GetTextExtentPoint32(hDC, szVolume, strlen(szVolume), &Size))
  1077. {
  1078. nError = -1;
  1079. goto DONE_ROUTINE;
  1080. }
  1081.     // Make the volume text there.
  1082.     if ((pFileInfo->hWndVol_TXT = CreateWindow(
  1083. "STATIC", 
  1084. szVolume, 
  1085. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  1086. cox,
  1087. coy,
  1088. DX_VOL_TXT, 
  1089. Size.cy,                
  1090. hWnd, 
  1091. (HMENU)idBase, 
  1092. hInst, 
  1093. NULL)) == NULL)
  1094. {
  1095. nError = -1;
  1096. goto DONE_ROUTINE;
  1097. }   
  1098.     coy += Size.cy;
  1099.     // Make the volume trackbars.
  1100.     // Create main volume bar.
  1101.     if ((pFileInfo->hWndVolM_TB = CreateWindow(
  1102. TRACKBAR_CLASS, 
  1103. "", 
  1104. WS_CHILD | WS_VISIBLE | TBS_VERT | TBS_BOTH, 
  1105. cox,
  1106. coy,
  1107. DX_VOL_TB, 
  1108. DY_VOL_TB,              
  1109. hWnd, 
  1110. (HMENU)(idBase+idVolMTB), 
  1111. hInst, 
  1112. NULL)) == NULL)
  1113. {
  1114. nError = -1;
  1115. goto DONE_ROUTINE;
  1116. }   
  1117.     SendMessage(pFileInfo->hWndVolM_TB, TBM_SETRANGE, FALSE, MAKELONG(MINVOL_TB, MAXVOL_TB)); 
  1118.     SendMessage(pFileInfo->hWndVolM_TB, TBM_SETPOS, TRUE, dwVol);
  1119.     pFileInfo->dwVol = MAXVOL_TB - dwVol;
  1120.     // Now the left volume.
  1121.     if ((pFileInfo->hWndVolL_TB = CreateWindow(
  1122. TRACKBAR_CLASS, 
  1123. "", 
  1124. WS_CHILD | WS_VISIBLE |WS_DISABLED| TBS_VERT | TBS_BOTH, 
  1125. cox+DX_VOL_TB+DX_VOLSPACING_TB,
  1126. coy,
  1127. DX_VOL_TB, 
  1128. DY_VOL_TB,              
  1129. hWnd, 
  1130. (HMENU)(idBase+idVolLTB), 
  1131. hInst, 
  1132. NULL)) == NULL)
  1133. {
  1134. nError = -1;
  1135. goto DONE_ROUTINE;
  1136. }   
  1137.     SendMessage(pFileInfo->hWndVolL_TB, TBM_SETRANGE, FALSE, MAKELONG(MINVOL_TB, MAXVOL_TB)); 
  1138.     SendMessage(pFileInfo->hWndVolL_TB, TBM_SETPOS, TRUE, MAXVOL_TB);
  1139.     if ((pFileInfo->hWndVolL_TXT = CreateWindow(
  1140. "STATIC", 
  1141. "L", 
  1142. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  1143. cox+DX_VOL_TB*3/2+DX_VOLSPACING_TB/2,
  1144. coy+DY_VOL_TB+DY_VOLSPACINGY,
  1145. DX_VOLUMECHAR, 
  1146. Size.cy,                
  1147. hWnd, 
  1148. (HMENU)0, 
  1149. hInst, 
  1150. NULL)) == NULL)
  1151. {
  1152. nError = -1;
  1153. goto DONE_ROUTINE;
  1154. }   
  1155.     // And right volume.
  1156.     if ((pFileInfo->hWndVolR_TB = CreateWindow(
  1157. TRACKBAR_CLASS, 
  1158. "", 
  1159. WS_CHILD | WS_VISIBLE | WS_DISABLED | TBS_VERT | TBS_BOTH, 
  1160. cox+DX_VOL_TB*2+DX_VOLSPACING_TB*2,
  1161. coy,
  1162. DX_VOL_TB, 
  1163. DY_VOL_TB,              
  1164. hWnd, 
  1165. (HMENU)(idBase+idVolRTB), 
  1166. hInst, 
  1167. NULL)) == NULL)
  1168. {
  1169. nError = -1;
  1170. goto DONE_ROUTINE;
  1171. }   
  1172.     SendMessage(pFileInfo->hWndVolR_TB,
  1173.     TBM_SETRANGE, FALSE, MAKELONG(MINVOL_TB, MAXVOL_TB)); 
  1174.     SendMessage(pFileInfo->hWndVolR_TB,
  1175.     TBM_SETPOS, TRUE, MAXVOL_TB);
  1176.     if ((pFileInfo->hWndVolR_TXT = CreateWindow(
  1177. "STATIC", 
  1178. "R", 
  1179. WS_CHILD | WS_VISIBLE | SS_LEFTNOWORDWRAP, 
  1180. cox+DX_VOL_TB*5/2+DX_VOLSPACING_TB/2+2,
  1181.     // +2 to look nice.
  1182. coy+DY_VOL_TB+DY_VOLSPACINGY,
  1183. DX_VOLUMECHAR, 
  1184. Size.cy,                
  1185. hWnd, 
  1186. (HMENU)0, 
  1187. hInst, 
  1188. NULL)) == NULL)
  1189. {
  1190. nError = -1;
  1191. goto DONE_ROUTINE;
  1192. }   
  1193.  
  1194.     coy += DY_VOL_TB + DY_BEFOREFIRSTBUTTON;    //Line under L & R
  1195.     if ((pFileInfo->hWndVol_EDGE = CreateWindow(
  1196. "STATIC", 
  1197. "", 
  1198. WS_CHILD | WS_VISIBLE | SS_ETCHEDHORZ, 
  1199. cox,
  1200. coy - (DY_BEFOREFIRSTBUTTON)/2,
  1201. DX_LINEEDGE, 
  1202. DY_LINEEDGE,                
  1203. hWnd, 
  1204. (HMENU)0, 
  1205. hInst, 
  1206. NULL)) == NULL)
  1207. {
  1208. nError = -1;
  1209. goto DONE_ROUTINE;
  1210. }   
  1211.     if (!GetTextExtentPoint32(hDC, szPlay, strlen(szPlay), &Size))
  1212. {
  1213. nError = -1;
  1214. goto DONE_ROUTINE;
  1215. }
  1216.     //Create Play Button
  1217.     if ((pFileInfo->hWndPlay_BN = CreateWindow(
  1218. "BUTTON", 
  1219. szPlay, 
  1220. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
  1221. cox,
  1222. coy,
  1223. DX_BUTTONSPACING, 
  1224. Size.cy + DY_BUTTONSPACING,             
  1225. hWnd, 
  1226. (HMENU)(idBase+idPlayBN), 
  1227. hInst, 
  1228. NULL)) == NULL)
  1229. {
  1230. nError = -1;
  1231. goto DONE_ROUTINE;
  1232. }       
  1233.     //coy += Size.cy + DY_BUTTONSPACING + DY_BETWEENBUTTONS;
  1234.     
  1235.     if (!GetTextExtentPoint32(hDC, szPlay, strlen(szPlay), &Size))
  1236. {
  1237. nError = -1;
  1238. goto DONE_ROUTINE;
  1239. }
  1240.      
  1241.     //Make Remove button
  1242.     if ((pFileInfo->hWndRemove_BN = CreateWindow(
  1243. "BUTTON", 
  1244. szRemove, 
  1245. WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 
  1246. cox + DX_BUTTONSPACING + DY_BETWEENBUTTONS,
  1247. coy,
  1248. DX_BUTTONSPACING, 
  1249. Size.cy + DY_BUTTONSPACING,             
  1250. hWnd, 
  1251. (HMENU)(idBase+idRemoveBN), 
  1252. hInst, 
  1253. NULL)) == NULL)
  1254. {
  1255. nError = -1;
  1256. goto DONE_ROUTINE;
  1257. }       
  1258.     coy += Size.cy + DY_BUTTONSPACING+ DY_BETWEENBUTTONS;
  1259.     //Set up Looped Checkbox 
  1260.     if (!GetTextExtentPoint32(hDC, szLooped, strlen(szLooped), &Size))
  1261. {
  1262. nError = -1;
  1263. goto DONE_ROUTINE;
  1264. }
  1265.     //Create Looped Checkbox window
  1266.     if ((pFileInfo->hWndLooped_BN = CreateWindow(
  1267. "BUTTON", 
  1268. szLooped, 
  1269. WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX, 
  1270. cox,
  1271. coy,
  1272. DX_LOOPED_TXT, 
  1273. Size.cy + DY_TEXTSPACING -2,               
  1274. hWnd, 
  1275. (HMENU)(idBase+idLoopedBN), 
  1276. hInst, 
  1277. NULL)) == NULL)
  1278. {
  1279. nError = -1;
  1280. goto DONE_ROUTINE;
  1281. }       
  1282.   
  1283.     // Don't need the between buttons spacing
  1284.     //  because there are no more controls.
  1285.     coy += Size.cy;// + DY_BUTTONSPACING; //+ DY_BETWEENBUTTONS;
  1286.     if ((pFileInfo->hWndWhole_EDGE = CreateWindow(
  1287. "STATIC", 
  1288. "", 
  1289. WS_CHILD | WS_VISIBLE | SS_ETCHEDFRAME, 
  1290. coxOld-DX_FRAMEEDGE,
  1291. coyOld-DY_FRAMEEDGE,
  1292. DX_CONTROLSPACING-DX_FRAMEEDGEINNER, 
  1293. coy - coyOld + DY_FRAMEEDGE*2,              
  1294. hWnd, 
  1295. (HMENU)0, 
  1296. hInst, 
  1297. NULL)) == NULL)
  1298. {
  1299. nError = -1;
  1300. goto DONE_ROUTINE;
  1301. }   
  1302.     
  1303.     SetAllText(pFileInfo);
  1304.     UpdateLRVolume(pFileInfo);
  1305.     
  1306. DONE_ROUTINE:   
  1307.     if (hDC != NULL)
  1308.     {
  1309. if (ReleaseDC(hWnd, hDC) == 0)
  1310. {
  1311. nError = -1;
  1312. goto DONE_ROUTINE;
  1313. }
  1314.     }
  1315.     return(nError);
  1316. }
  1317. // =======================================================================
  1318. /*  This will add to the linked list of FileInfo's.
  1319.     The FileInfo's keep track of the
  1320.     files loaded, and this is done in a linked list format
  1321.     Input:
  1322. pFileInfoHead   -   Top of linked list.
  1323. pFileInfo   -   Pointer to entry to add.
  1324.     Output:
  1325. 0 if successful, else the error code.
  1326. */      
  1327. // =======================================================================
  1328. int AddToList(FILEINFO *pFileInfoHead, FILEINFO *pFileInfo)
  1329. {
  1330.     pFileInfo->pNext = NULL;    
  1331.     pFileInfo->fPlaying = FALSE;
  1332.     while (pFileInfoHead->pNext != NULL)
  1333. {
  1334. pFileInfoHead = pFileInfoHead->pNext;
  1335. }
  1336.     pFileInfoHead->pNext = pFileInfo;
  1337.     return(0);
  1338. }
  1339. // =======================================================================
  1340. /*  This routine will get the number of controls in the window.
  1341.     Can be used to determine new size of window.
  1342.     Input:
  1343. pFileInfoHead           -   Header of linked list.
  1344.     Output:
  1345. # of controls.
  1346. */
  1347. // =======================================================================
  1348. int GetNumControls( FILEINFO *pFileInfoHead )
  1349. {
  1350.     int cT  = 0;
  1351.     while (pFileInfoHead->pNext != NULL)
  1352.     {
  1353.     pFileInfoHead = pFileInfoHead->pNext;
  1354.     cT++;
  1355.     }
  1356.     return(cT);
  1357. }
  1358. // =======================================================================
  1359. /*  This routine will free the whole linked list in pFileInfoFirst,
  1360.     including all the
  1361.     memory used by the wave file, waveformatex structure, etc.
  1362. */
  1363. // =======================================================================
  1364. int FreeAllList(HWND hWnd, FILEINFO *pFileInfoFirst)
  1365. {
  1366.     FILEINFO        *pFileInfo, *pFileNext;
  1367.     UINT        cT;
  1368.     Assert(pFileInfoFirst != NULL);
  1369.     pFileInfo = pFileInfoFirst->pNext;
  1370.     while (pFileInfo != NULL)
  1371.     {
  1372.     ReleaseDirectSoundBuffer(pFileInfo);
  1373.     GlobalFreePtr(pFileInfo->pwfx);
  1374.     GlobalFreePtr(pFileInfo->pbData);
  1375.     pFileNext = pFileInfo->pNext;
  1376.     GlobalFreePtr(pFileInfo);
  1377.     pFileInfo = pFileNext;
  1378.     }
  1379.     for (cT=0; cT<MAXCONTROLS; cT++)
  1380.     rgfcoxAvail[cT] = FALSE;
  1381.     return(0);          
  1382. }
  1383. // =======================================================================
  1384. /*  This routine will remove an entry from the list, i.e. will remove
  1385.     pFileInfo and all its allocated memory from the list pointed by the header
  1386.     by pFileInfoHead
  1387.     Input:
  1388. pFileInfo               -   Pointer to entry to remove.
  1389. pFileInfoHead           -   Head, first entry.
  1390.     Output:
  1391. 0 if successful, else the error.
  1392. */
  1393. // =======================================================================
  1394. int RemoveFromList(FILEINFO *pFileInfo, FILEINFO *pFileInfoHead)
  1395. {
  1396.     FILEINFO        *pFileNext;
  1397.     Assert(pFileInfoHead != NULL);
  1398.     // This used to be pFileInfoHead != NULL
  1399.     while (pFileInfoHead->pNext != NULL)
  1400. {
  1401. if (pFileInfoHead->pNext == pFileInfo)
  1402.     {
  1403.     Assert(pFileInfo->cox/DX_CONTROLSPACING < MAXCONTROLS);
  1404.     rgfcoxAvail[pFileInfo->cox/DX_CONTROLSPACING] = FALSE;
  1405.    
  1406.     DestroyWindow(pFileInfo->hWndFileName_TXT); 
  1407.     DestroyWindow(pFileInfo->hWndFreq_TB);      
  1408.     DestroyWindow(pFileInfo->hWndFreq_TXT);     
  1409.     DestroyWindow(pFileInfo->hWndPan_TB);           
  1410.     DestroyWindow(pFileInfo->hWndPan_TXT);      
  1411.     DestroyWindow(pFileInfo->hWndVol_TXT);      
  1412.     DestroyWindow(pFileInfo->hWndVolL_TB);      
  1413.     DestroyWindow(pFileInfo->hWndVolR_TB);      
  1414.     DestroyWindow(pFileInfo->hWndVolM_TB);      
  1415.     DestroyWindow(pFileInfo->hWndLooped_BN);        
  1416.     DestroyWindow(pFileInfo->hWndPlay_BN);      
  1417.     DestroyWindow(pFileInfo->hWndRemove_BN);
  1418.     DestroyWindow(pFileInfo->hWndFileName_EDGE);
  1419.     DestroyWindow(pFileInfo->hWndLooped_EDGE);  
  1420.     DestroyWindow(pFileInfo->hWndFreq_EDGE);        
  1421.     DestroyWindow(pFileInfo->hWndPan_EDGE);     
  1422.     DestroyWindow(pFileInfo->hWndVol_EDGE);     
  1423.     DestroyWindow(pFileInfo->hWndWhole_EDGE);       
  1424.     DestroyWindow(pFileInfo->hWndVolL_TXT);     
  1425.     DestroyWindow(pFileInfo->hWndVolR_TXT);     
  1426.     #ifdef SHOWSTATUS
  1427.     DestroyWindow(pFileInfo->hWndStatus_TXT);
  1428.     DestroyWindow(pFileInfo->hWndStatus_EDGE);
  1429.     DestroyWindow(pFileInfo->hWndPlayPosition_TXT);
  1430.     DestroyWindow(pFileInfo->hWndPlayPosition_EDGE);
  1431.     DestroyWindow(pFileInfo->hWndWritePosition_TXT);
  1432.     DestroyWindow(pFileInfo->hWndWritePosition_EDGE);
  1433.     #endif
  1434.     GlobalFree(pFileInfoHead->pNext->pwfx);
  1435.     GlobalFree(pFileInfoHead->pNext->pbData);
  1436.     pFileNext = pFileInfoHead->pNext->pNext;
  1437.     GlobalFreePtr(pFileInfoHead->pNext);
  1438.     pFileInfoHead->pNext = pFileNext;                                                         
  1439.     break;
  1440.     }
  1441. pFileInfoHead = pFileInfoHead->pNext;
  1442. }
  1443.     return(0);
  1444. }
  1445. // =======================================================================
  1446. /*  This will pop up the open file dialog and allow the user to pick one file. 
  1447.     
  1448.     Input:  
  1449. hWnd            -   Handle of parent window.
  1450. pszFileName         -   String to store filename in, must be at least MAX_PATH long.
  1451.     Output:
  1452. TRUE if a file was  picked successfully, else FALSE (user didn't pick a file)
  1453.  */
  1454. // =======================================================================
  1455. BOOL OpenFileDialog(HWND hWnd, LPSTR pszFileName, int *nFileName, LPBOOL lpfSticky)
  1456. {
  1457.     BOOL            fReturn,
  1458.     fValid;
  1459.     OPENFILENAME    ofn;                
  1460.     pszFileName[0]          = 0;
  1461.     ofn.lStructSize         = sizeof(ofn);
  1462.     ofn.hwndOwner           = hWnd;
  1463.     ofn.hInstance           = hInst;
  1464.     ofn.lpstrFilter         = "Wave Files*.wavAll Files*.*";
  1465.     ofn.lpstrCustomFilter   = NULL;
  1466.     ofn.nMaxCustFilter      = 0;
  1467.     ofn.nFilterIndex        = 1;
  1468.     ofn.lpstrFile           = pszFileName;
  1469.     ofn.nMaxFile            = MAX_PATH;
  1470.     ofn.lpstrFileTitle      = NULL;
  1471.     ofn.nMaxFileTitle       = 0;
  1472.     ofn.lpstrInitialDir     = gszCDStartPath;
  1473.     ofn.lpstrTitle          = "File Open";
  1474.     ofn.Flags               = OFN_FILEMUSTEXIST | OFN_EXPLORER
  1475.                                 | OFN_ENABLETEMPLATE | OFN_ENABLEHOOK | OFN_HIDEREADONLY;
  1476.     ofn.nFileOffset         = 0;
  1477.     ofn.nFileExtension      = 0;
  1478.     ofn.lpstrDefExt         = "wav";
  1479.     ofn.lCustData           = (LONG)lpfSticky;
  1480.     ofn.lpfnHook            = FileOpenCustomTemplateDlgProc;
  1481.     ofn.lpTemplateName      = MAKEINTRESOURCE(IDD_FILEOPEN_NEST);
  1482.     fValid = FALSE;
  1483.     do   {    
  1484.     if (fReturn = GetOpenFileName(&ofn))
  1485.     {                               
  1486. // Set the start path for the next time this dialog is opened
  1487.         lstrcpy( gszCDStartPath, pszFileName );
  1488.         gszCDStartPath[ofn.nFileOffset] = '';
  1489. fValid = IsValidWave(pszFileName);
  1490. if (!fValid)
  1491. {
  1492. MessageBox(hWnd, "Wave files must be PCM format!",
  1493.        "Invalid Wave File", MB_OK|MB_ICONSTOP);
  1494. }
  1495. else
  1496. *nFileName = ofn.nFileOffset;
  1497.     }
  1498.     else fValid = TRUE;         // Force break out of loop.
  1499.     
  1500.     } while (!fValid);
  1501.     return(fReturn);     
  1502. }
  1503. // =======================================================================
  1504. /*  This function will determine if the filename passed
  1505.     in is a valid wave for this
  1506.     app, that is a PCM wave.
  1507.     Input:
  1508. pszFileName -   FileName to check.
  1509.     Output:
  1510. FALSE if not a valid wave, TRUE if it is.
  1511.     
  1512. */
  1513. // =======================================================================
  1514. BOOL IsValidWave(LPSTR pszFileName)
  1515.     BOOL            fReturn     = FALSE;
  1516.     int             nError      = 0;
  1517.     HMMIO           hmmio;
  1518.     MMCKINFO        mmck;
  1519.     WAVEFORMATEX    *pwfx;
  1520.     if ((nError = WaveOpenFile(pszFileName, &hmmio, &pwfx, &mmck)) != 0)
  1521. {       
  1522. goto ERROR_IN_ROUTINE;
  1523. }
  1524.     if (pwfx->wFormatTag != WAVE_FORMAT_PCM) 
  1525. {
  1526. goto ERROR_IN_ROUTINE;
  1527. }
  1528.     WaveCloseReadFile(&hmmio, &pwfx);
  1529.     fReturn = TRUE;
  1530. ERROR_IN_ROUTINE:
  1531.     return(fReturn);    
  1532. }
  1533. // =======================================================================
  1534. // =======================================================================
  1535. BOOL UIMainWindowVSBHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1536. {
  1537.     FILEINFO    *pFileInfo;
  1538.     BOOL        fReturn             = FALSE;
  1539.     pFileInfo = FileInfoFirst.pNext;
  1540.     Assert(pFileInfo != NULL);
  1541.     while (pFileInfo != NULL)
  1542.     {
  1543.     if ((HWND)lParam == pFileInfo->hWndVolM_TB)
  1544.     {
  1545. pFileInfo->dwVol = MAXVOL_TB -
  1546. SendMessage(pFileInfo->hWndVolM_TB, TBM_GETPOS, 0, 0);
  1547. ChangeOutputVol(pFileInfo);
  1548. SetAllText(pFileInfo);
  1549. UpdateLRVolume(pFileInfo);
  1550. fReturn = TRUE;
  1551.     }
  1552.     pFileInfo = pFileInfo->pNext;
  1553.     
  1554.     }
  1555.     return (fReturn);
  1556. }
  1557. // =======================================================================
  1558. /*  This routine will handle all the calls to the WM_HSCROLL
  1559.     for the main window, that
  1560.     is, all the horizontal scrollbar (and trackbar) messages.
  1561.     Input:
  1562. Standard parameters (minus the "message" parameter)
  1563. for a window callback, though
  1564. this is called from the window callback.
  1565.     Output:
  1566. FALSE if the message isn't processed, else TRUE if it is.
  1567. If FALSE, the
  1568. return procedure should call the default windows procedure.
  1569. */
  1570. // =======================================================================
  1571. BOOL UIMainWindowHSBHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1572. {
  1573.     FILEINFO    *pFileInfo;
  1574.     BOOL        fReturn             = FALSE;
  1575.     pFileInfo = FileInfoFirst.pNext;
  1576.     
  1577.     Assert(pFileInfo != NULL);
  1578.     while (pFileInfo != NULL)
  1579.     {
  1580.     if ((HWND)lParam == pFileInfo->hWndFreq_TB)
  1581.     {
  1582. pFileInfo->dwFreq = (SendMessage(pFileInfo->hWndFreq_TB,
  1583. TBM_GETPOS, 0, 0) * FREQFACTOR) - FREQADD;
  1584. ChangeOutputFreq(pFileInfo);
  1585. SetAllText(pFileInfo);          
  1586. fReturn = TRUE;
  1587.     }
  1588.     else if ((HWND)lParam == pFileInfo->hWndPan_TB)
  1589.     {
  1590. pFileInfo->dwPan = SendMessage(pFileInfo->hWndPan_TB,
  1591.        TBM_GETPOS, 0, 0);
  1592. ChangeOutputPan(pFileInfo);
  1593. SetAllText(pFileInfo);
  1594. UpdateLRVolume(pFileInfo);
  1595. fReturn = TRUE;
  1596.     }
  1597.     pFileInfo = pFileInfo->pNext;
  1598.     
  1599.     }
  1600.     return (fReturn);
  1601. }
  1602. // =======================================================================
  1603. /*  This routine will handle all the calls to the WM_COMMAND
  1604.     for the main window.
  1605.     Input:
  1606.     Standard parameters (minus the "message" parameter)
  1607.     for a window callback, though
  1608.     this is called from the window callback.
  1609.     Output:
  1610. FALSE if the message isn't processed, else TRUE if it is.
  1611. If FALSE, the
  1612. return procedure should call the default windows procedure.
  1613. */
  1614. // =======================================================================
  1615. BOOL UIMainWindowCMDHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1616. {
  1617.     BOOL        fReturn     = FALSE;
  1618.     FILEINFO        *pFileInfo;
  1619.     FILEINFO        *pFileInfoNext;
  1620.     DWORD       dwLooping;
  1621.     pFileInfo = FileInfoFirst.pNext;
  1622.     while (pFileInfo != NULL)
  1623.     {
  1624.     
  1625.     pFileInfoNext = pFileInfo->pNext;
  1626.     
  1627.     if ((HWND)lParam == pFileInfo->hWndLooped_BN)
  1628.     {
  1629. pFileInfo->fLooped = SendMessage(pFileInfo->hWndLooped_BN,
  1630.  BM_GETCHECK, 0, 0);
  1631. // If it is playing then reset the looping to be proper
  1632. if( pFileInfo->fPlaying ) {
  1633. if( pFileInfo->fLooped ) {
  1634.     dwLooping = DSBPLAY_LOOPING;
  1635. } else {
  1636.     dwLooping = 0;
  1637. }
  1638. pFileInfo->pDSB->lpVtbl->Play(pFileInfo->pDSB,
  1639. 0, 0, dwLooping );
  1640. fReturn = TRUE;
  1641.     }
  1642.     else if ((HWND)lParam == pFileInfo->hWndPlay_BN)
  1643.     {
  1644. if (pFileInfo->fPlaying)
  1645. {
  1646. if (StopDSound(hWnd, pFileInfo) == 0)
  1647. {
  1648.     SendMessage((HWND)lParam,
  1649. WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szPlay);
  1650. #ifdef SHOWSTATUS
  1651.     UpdateStatus(pFileInfo, 0);
  1652. #endif
  1653.     
  1654.     fReturn = TRUE;
  1655.     break;
  1656. }
  1657. }
  1658. else            
  1659. {
  1660. if (StartDSound(hWnd, pFileInfo) == 0)
  1661. {
  1662.     SendMessage((HWND)lParam,
  1663. WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szStop);
  1664. #ifdef SHOWSTATUS
  1665.     UpdateStatus(pFileInfo, DSBSTATUS_PLAYING);
  1666. #endif
  1667.     
  1668.     fReturn = TRUE;
  1669.     break;
  1670. }
  1671. }
  1672. fReturn = TRUE;
  1673.     }
  1674.     else if ((HWND)lParam == pFileInfo->hWndRemove_BN)
  1675.     {
  1676. ReleaseDirectSoundBuffer(pFileInfo);
  1677. RemoveFromList(pFileInfo, &FileInfoFirst);
  1678.         UpdateMainStatus();
  1679. fReturn = TRUE;
  1680.     }
  1681.     pFileInfo = pFileInfoNext;
  1682.     
  1683.     }
  1684.     
  1685.     if (!fReturn)
  1686.     {
  1687.     switch(wParam)
  1688.     {
  1689. case IDPD_FILE_EXIT:    
  1690. PostMessage(hWnd, WM_CLOSE, 0, 0);
  1691. break;
  1692. case IDPD_FILE_OPEN:
  1693. PD_FileOpen(hWnd);
  1694. break;
  1695.     
  1696. case IDPD_HELP_ABOUT:
  1697. DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUT),
  1698.       hWnd, (DLGPROC)DLGHelpAbout);
  1699. break;
  1700. case IDPD_OPTIONS_OUTPUTTYPE:
  1701. DialogBox(hInst, MAKEINTRESOURCE(IDD_OUTPUTBUFFERTYPE),
  1702.       hWnd, (DLGPROC)DLGOutputBufferType);
  1703. break;
  1704. case IDPD_CHECKLATENCY:
  1705. StopAllDSounds(hWnd, &FileInfoFirst);
  1706. // Now fake that we're on in each voice so the
  1707. //timer will update the 
  1708. // strings in the window.
  1709. pFileInfo = FileInfoFirst.pNext;
  1710. while (pFileInfo != NULL)
  1711. {                                           
  1712.     pFileInfo->fPlaying = TRUE;
  1713.     pFileInfo = pFileInfo->pNext;       
  1714. }
  1715. DialogBox(hInst, MAKEINTRESOURCE(IDD_CHECKLATENCY),
  1716.       hWnd, (DLGPROC)DLGCheckLatency);
  1717. break;
  1718.     case IDPD_ENUMDRIVERS:
  1719. fEnumDrivers = !fEnumDrivers;
  1720. if( fEnumDrivers )
  1721.     {
  1722.     MessageBox( hWnd,
  1723.     "Drivers will not be enumerated until DSSHOW is run again.",
  1724.     szAppName, MB_OK );
  1725.     }
  1726. break;
  1727. default:
  1728. return(FALSE);
  1729.     }
  1730.     }
  1731.     return(TRUE);
  1732. }
  1733. // =======================================================================
  1734. /*  This routine will handle the timer messages.
  1735.     Input:
  1736. Standard input.
  1737.     Output: 
  1738. TRUE if processed message, otherwise FALSE
  1739. */
  1740. // =======================================================================
  1741. BOOL UIMainWindowTimerHandler(HWND hWnd, WPARAM wParam, LPARAM lParam)
  1742. {
  1743.     FILEINFO        *pFileInfo;
  1744.     BOOL            fReturn             = FALSE;
  1745.     DWORD           dwStatus            = 0;
  1746.     for (pFileInfo = FileInfoFirst.pNext; pFileInfo != NULL; pFileInfo = pFileInfo->pNext)
  1747.     {
  1748.     HRESULT hr;
  1749.     hr = IDirectSoundBuffer_GetStatus(pFileInfo->pDSB, &dwStatus);
  1750.     if (DS_OK != hr) continue;
  1751.     if (dwStatus & DSBSTATUS_BUFFERLOST) {
  1752. LPBYTE pbData, pbData2;
  1753. DWORD  dwLength, dwLength2;
  1754. //
  1755. //  Restore the buffer, rewrite data, and play
  1756. //
  1757. hr = IDirectSoundBuffer_Restore(pFileInfo->pDSB);
  1758. if (DS_OK == hr) {
  1759. hr = IDirectSoundBuffer_Lock(pFileInfo->pDSB, 0,
  1760.  pFileInfo->cbSize,
  1761.  &pbData, &dwLength,
  1762.  &pbData2, &dwLength2,
  1763.  0);
  1764. if (DS_OK == hr) {
  1765.     Assert(pbData != NULL);
  1766.     Assert(pFileInfo->pbData != NULL);
  1767.     memcpy(pbData, pFileInfo->pbData, pFileInfo->cbSize);
  1768.     hr = IDirectSoundBuffer_Unlock(pFileInfo->pDSB,
  1769.        pbData, dwLength,
  1770.        NULL, 0);
  1771.     if (DS_OK == hr) {
  1772.     if (pFileInfo->fPlaying) {
  1773. if (pFileInfo->fLooped) {
  1774. IDirectSoundBuffer_Play( pFileInfo->pDSB, 0, 0,
  1775.  DSBPLAY_LOOPING );
  1776. } else {
  1777. IDirectSoundBuffer_Play( pFileInfo->pDSB, 0, 0,
  1778.  0 );
  1779. }
  1780.     }
  1781.     IDirectSoundBuffer_GetStatus(pFileInfo->pDSB, &dwStatus);
  1782.     }
  1783. }
  1784. }
  1785.     }
  1786. #ifdef SHOWSTATUS
  1787.     UpdateStatus(pFileInfo, dwStatus);
  1788. #endif
  1789.     if (!(dwStatus & DSBSTATUS_BUFFERLOST))
  1790.     {
  1791. if ((pFileInfo->fPlaying) && (!(dwStatus & DSBSTATUS_PLAYING)) )
  1792. {
  1793. if (StopDSound(hWnd, pFileInfo) == 0)
  1794. {
  1795.     SendMessage(pFileInfo->hWndPlay_BN,
  1796. WM_SETTEXT, 0, (LPARAM)(LPCTSTR)szPlay);
  1797. }
  1798. }
  1799.     }
  1800.     pFileInfo->fLost = dwStatus & DSBSTATUS_BUFFERLOST;
  1801.     fReturn = TRUE;
  1802.     }
  1803.     return (fReturn);
  1804. }   
  1805. // =======================================================================
  1806. /*  This routine will start a sound to be played.  
  1807.     Input:
  1808. hWnd        -   Of parent window.
  1809. pFileInfo   -   Pointer to file to start,
  1810. which is loaded and the
  1811. data is filled in the structure,
  1812. such as pbData, 
  1813. etc.
  1814.     Output:
  1815. 0 if successful, else the error code.
  1816. */
  1817. // =======================================================================
  1818. int StartDSound(HWND hWnd, FILEINFO *pFileInfo)
  1819. {
  1820.     HRESULT     hr              = 0;
  1821.     DWORD           dwLooped;
  1822.     DWORD           dwStatus                = 0;
  1823.     // Already playing?
  1824.     // Start sound here....
  1825.     dwLooped = 0;
  1826.     if (pFileInfo->fLooped) {
  1827.     dwLooped = DSBPLAY_LOOPING;
  1828.     }
  1829.     
  1830.     if ((hr = pFileInfo->pDSB->lpVtbl->GetStatus(pFileInfo->pDSB,
  1831.  &dwStatus)) == 0)
  1832.     {
  1833.     if ((dwStatus&DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
  1834.     {
  1835. // Don't bother playing, just restart
  1836. if ((hr = pFileInfo->pDSB->lpVtbl->SetCurrentPosition(
  1837.     pFileInfo->pDSB, 0)) != 0)
  1838. {
  1839. MessageBox(hWnd, "Cannot set current position",
  1840.        "Direct Sound Error", MB_OK);
  1841. }
  1842.     }
  1843.     // Yes gotos are bad but this is real life not school.
  1844.     else goto PLAY_THE_THING;           
  1845.     }
  1846.     
  1847.     else
  1848.     {
  1849. PLAY_THE_THING:
  1850.     if ((hr = pFileInfo->pDSB->lpVtbl->Play(pFileInfo->pDSB,
  1851.     0, 0, dwLooped)) != 0)
  1852.     {
  1853.     MessageBox(hWnd, "Cannot start playing",
  1854.    "Direct Sound Error", MB_OK);
  1855.     }
  1856.     else
  1857.     pFileInfo->fPlaying = TRUE;
  1858.     }
  1859.     return(hr);
  1860. }
  1861. // =======================================================================
  1862. /*  This routine will stop a sound which is playing.
  1863.     Input:
  1864. hWnd        - Of parent window.
  1865. pFileInfo       - Pointer to file to stop playing.
  1866.     Output:
  1867. 0 if successful, else the error code.
  1868. */
  1869. // =======================================================================
  1870. int StopDSound(HWND hWnd, FILEINFO *pFileInfo)
  1871. {
  1872.     HRESULT     hr          = 0;
  1873.     if (!pFileInfo->fPlaying)
  1874.     return(0);
  1875.    
  1876.     // Stop sound here...
  1877.     if ((hr = pFileInfo->pDSB->lpVtbl->Stop(pFileInfo->pDSB)) != 0) 
  1878.     {
  1879.     MessageBox(hWnd, "Cannot stop sound",
  1880.    "Direct Sound Error", MB_OK);        
  1881.     }
  1882.     else
  1883.     pFileInfo->fPlaying = FALSE;    
  1884.     return(hr);
  1885. }
  1886. // =======================================================================
  1887. /*  This routine will stop all the sounds which are playing.
  1888.     Input:
  1889. hWnd        - Of parent window.
  1890. pFileInfo   - Pointer to file to stop playing.
  1891. (i.e. the head)
  1892.     Output:
  1893. 0 if successful, else the error code.
  1894. */
  1895. // =======================================================================
  1896. int StopAllDSounds(HWND hWnd, FILEINFO *pFileInfo)
  1897. {
  1898.     while (pFileInfo->pNext != NULL)
  1899. {
  1900. StopDSound(hWnd, pFileInfo->pNext);
  1901. pFileInfo = pFileInfo->pNext;       
  1902. }
  1903.     return(0);
  1904. }
  1905. // =======================================================================
  1906. /*  This routine will set the freq, vol and pan slider text
  1907.     according to the value 
  1908.     passed in.
  1909.     Input:
  1910. pFileInfo   -   File pointer to set frequency for.
  1911.     The dwFreq in the pFileInfo structure must be set.
  1912.     This also uses the window handle
  1913.     in the pFileInfo structure.
  1914.     
  1915.     Output:
  1916. None.
  1917. */
  1918. // =======================================================================
  1919. void SetAllText(FILEINFO    *pFileInfo)
  1920. {
  1921.     char            szBufT[128];
  1922.     sprintf(szBufT, "%s: %lu Hz     ",
  1923. szFreq, pFileInfo->dwFreq);
  1924.     SetWindowText(pFileInfo->hWndFreq_TXT, szBufT);
  1925.     // Change PAN val to show full range
  1926.     sprintf(szBufT, "%s: %ld", szPan,
  1927. (((LONG)(pFileInfo->dwPan) + SHIFTPAN_TB) * MULTPAN_TB ) );
  1928.     SetWindowText(pFileInfo->hWndPan_TXT, szBufT);
  1929.     // Change VOLUME val to show full range
  1930.     sprintf(szBufT, "%s: %ld", szVolume,
  1931. (((LONG)(pFileInfo->dwVol) + SHIFTVOL_TB) * MULTVOL_TB ));
  1932.     SetWindowText(pFileInfo->hWndVol_TXT, szBufT);
  1933. }
  1934. // =======================================================================
  1935. /*  This routine will update the left and right
  1936.     volume according to main volume 
  1937.     and pan.
  1938.     Input:
  1939. pFileInfo   - Pointer to fileinfo to update.
  1940.     Output:
  1941. Nothing worth using.
  1942. */
  1943. // =======================================================================
  1944. void UpdateLRVolume(FILEINFO *pFileInfo)
  1945. {
  1946.     int             volLeft, volRight;
  1947.     if (pFileInfo->dwPan < MIDPAN_TB)
  1948.     {
  1949.     volLeft = pFileInfo->dwVol;
  1950.     volRight = (((int)pFileInfo->dwPan)
  1951.     *(int)pFileInfo->dwVol)/((int)MIDPAN_TB);
  1952.     }
  1953.     else
  1954.     {
  1955.     volLeft = ((((int)pFileInfo->dwPan - MAXPAN_TB)*-1)
  1956.    *(int)pFileInfo->dwVol)/((int)MIDPAN_TB);
  1957.     volRight = pFileInfo->dwVol;
  1958.     }
  1959.     SendMessage(pFileInfo->hWndVolL_TB, TBM_SETPOS, TRUE, MAXVOL_TB-volLeft);
  1960.     SendMessage(pFileInfo->hWndVolR_TB, TBM_SETPOS, TRUE, MAXVOL_TB-volRight);
  1961.     
  1962. }
  1963. // =======================================================================
  1964. /*  This will change the output panning position for a certain FILEINFO.
  1965.     This is 
  1966.     done by sending messages to the direct sound driver 
  1967.     Input:  
  1968. pFileInfo   -   FileInfo to set.  This must contain the
  1969. panning value to set.
  1970.     Output:
  1971. 0 if successful, else the error code.
  1972. */
  1973. // =======================================================================
  1974. int ChangeOutputPan(FILEINFO *pFileInfo)
  1975. {
  1976.     HRESULT     hr      = 0;
  1977.     // Change PAN val  since TB does not go full range
  1978.     if ((hr = pFileInfo->pDSB->lpVtbl->SetPan(pFileInfo->pDSB,
  1979. (((pFileInfo->dwPan) + SHIFTPAN_TB) * MULTPAN_TB) )) != 0)
  1980.     {
  1981. goto ERROR_DONE_ROUTINE;
  1982.     }
  1983. ERROR_DONE_ROUTINE:
  1984.     return(hr);
  1985. }
  1986. // =======================================================================
  1987. /*  This will change the output freq for a certain FILEINFO.  This is 
  1988.     done by sending messages to the direct sound driver 
  1989.     Input:  
  1990. pFileInfo                   -   FileInfo to set.  This must contain the
  1991. freq value to set.
  1992.     Output:
  1993. 0 if successful, else the error code.
  1994. */
  1995. // =======================================================================
  1996. int ChangeOutputFreq(FILEINFO *pFileInfo)
  1997. {
  1998.     HRESULT     hr      = 0;
  1999.     if ((hr = pFileInfo->pDSB->lpVtbl->SetFrequency(pFileInfo->pDSB, pFileInfo->dwFreq)) != 0)
  2000. {
  2001. goto ERROR_DONE_ROUTINE;
  2002. }
  2003. ERROR_DONE_ROUTINE:
  2004.     return(hr);
  2005. }
  2006. // =======================================================================
  2007. /*  This will change the output vol for a certain FILEINFO.  This is 
  2008.     done by sending messages to the direct sound driver 
  2009.     Input:  
  2010. pFileInfo                   -   FileInfo to set.  This must contain the
  2011. freq value to set.
  2012.     Output:
  2013. 0 if successful, else the error code.
  2014. */
  2015. // =======================================================================
  2016. int ChangeOutputVol(FILEINFO *pFileInfo)
  2017. {
  2018.     HRESULT     hr      = 0;
  2019.     // Shift VOLUME val by 4 bits since TB does not go full range
  2020.     if ((hr = pFileInfo->pDSB->lpVtbl->SetVolume(pFileInfo->pDSB,
  2021. (((pFileInfo->dwVol) + SHIFTVOL_TB) * MULTVOL_TB) )) != 0)
  2022. {
  2023. goto ERROR_DONE_ROUTINE;
  2024. }
  2025. ERROR_DONE_ROUTINE:
  2026.     return(hr);
  2027. }
  2028. // =======================================================================
  2029. /*  This is the dialog box handler for the check latency dialog box.
  2030.     Input:
  2031. Standard dialog box input.
  2032.     Output:
  2033. Standard dialog box output.
  2034. */
  2035. // =======================================================================
  2036. long FAR PASCAL DLGCheckLatency(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2037. {
  2038.     static HWND     hWndFiles_LB;
  2039.     FILEINFO        *pFileInfo              = NULL;
  2040.     int         nSelected;
  2041.     int         cT;
  2042.     switch(uMsg)
  2043.     {
  2044.     case WM_INITDIALOG:
  2045. hWndFiles_LB = GetDlgItem(hWnd, IDC_FILES_LB);
  2046. pFileInfo = FileInfoFirst.pNext;
  2047. while (pFileInfo != NULL)
  2048. {               
  2049. SendMessage(hWndFiles_LB,
  2050. LB_ADDSTRING,
  2051. 0,
  2052. (LPARAM)(pFileInfo->szFileName
  2053.      + pFileInfo->nFileName));
  2054. pFileInfo = pFileInfo->pNext;       
  2055. }
  2056. break;      
  2057.     case WM_COMMAND:
  2058. switch(wParam)
  2059. {
  2060. case ID_DONE:                   
  2061.     PostMessage(hWnd, WM_CLOSE, 0, 0);
  2062.     break;
  2063.     
  2064. case ID_PLAY:                       
  2065.     if ((nSelected = SendMessage(hWndFiles_LB,
  2066.  LB_GETCURSEL, 0, 0))
  2067. != LB_ERR)
  2068.     {
  2069.     for (cT=0, pFileInfo = FileInfoFirst.pNext;
  2070. pFileInfo != NULL;
  2071. pFileInfo = pFileInfo->pNext, cT++)
  2072.     {
  2073. if (cT == nSelected)
  2074. {
  2075. StartDSound(hWnd, pFileInfo);
  2076. break;
  2077. }
  2078.     }
  2079.     
  2080.     }
  2081.     
  2082.     break;
  2083.     
  2084. case ID_STOP:
  2085.     StopAllDSounds(hWnd, &FileInfoFirst);
  2086.     break;
  2087.     
  2088. default:
  2089.     break;
  2090.     
  2091. }
  2092. break;
  2093.     case WM_CLOSE:
  2094. StopAllDSounds(hWnd, &FileInfoFirst);
  2095. EndDialog(hWnd, 0);
  2096. break;
  2097.     default:
  2098. return(0);
  2099. break;               
  2100.     }
  2101.     
  2102.     return(1);
  2103. }
  2104. // =======================================================================
  2105. /*  The help about dialog procedure.  
  2106.     
  2107.     Input:
  2108. Standard windows dialog procedure.
  2109.     Output:
  2110. Standard windows dialog procedure.
  2111. */
  2112. // =======================================================================
  2113. long FAR PASCAL DLGHelpAbout(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2114. {
  2115.     switch(uMsg)
  2116.     {
  2117.     case WM_INITDIALOG:
  2118. break;      
  2119.     case WM_COMMAND:
  2120. switch(wParam)
  2121. {
  2122. case ID_OK:                 
  2123.     PostMessage(hWnd, WM_CLOSE, 0, 0);
  2124.     break;
  2125.     
  2126. default:
  2127.     break;
  2128.     
  2129. }
  2130. break;
  2131.     case WM_CLOSE:
  2132. EndDialog(hWnd, 0);
  2133. break;
  2134.     default:
  2135. return(0);
  2136. break;               
  2137.     }
  2138.     
  2139.     return(1);
  2140. }
  2141. // =======================================================================
  2142. /*  The help about dialog procedure.  
  2143.     
  2144.     Input:
  2145. Standard windows dialog procedure.
  2146.     Output:
  2147. Standard windows dialog procedure.
  2148. */
  2149. // =======================================================================
  2150. long FAR PASCAL DLGOutputBufferType(HWND hWnd,UINT uMsg, WPARAM wParam, LPARAM lParam)
  2151. {
  2152.     static HWND     hWndFormats_LB          = NULL;
  2153.     int         cT;
  2154.     int         nSelection;
  2155.      
  2156.     switch(uMsg)
  2157.     {
  2158.     case WM_INITDIALOG:
  2159. // Get the windows we need.
  2160. hWndFormats_LB = GetDlgItem(hWnd, IDC_FORMATS);
  2161. // Put the strings in the list box.
  2162. for (cT=0; cT<C_DROPDOWNPCMFORMATS; cT++)
  2163. SendMessage(hWndFormats_LB,
  2164. LB_ADDSTRING, 0, (LPARAM)rgszTypes[cT]);
  2165. // Get the current format and highlight it in the list box.
  2166. if ((nSelection = FormatToIndex(hWnd, &FileInfoFirst)) != LB_ERR)
  2167. {
  2168. SendMessage(hWndFormats_LB, LB_SETCURSEL, nSelection, 0);
  2169. }
  2170. break;      
  2171.     case WM_COMMAND:
  2172.     switch(LOWORD(wParam))
  2173. {
  2174. case IDC_FORMATS:
  2175.     if( HIWORD( wParam ) == LBN_DBLCLK )
  2176. {
  2177. SendMessage( hWnd, WM_COMMAND, MAKEWPARAM( ID_OK, 0 ),
  2178. 0L );
  2179. }
  2180.     break;
  2181. case ID_OK:
  2182.     if ((nSelection = SendMessage(hWndFormats_LB,
  2183. LB_GETCURSEL, 0, 0)) != LB_ERR)
  2184.     {
  2185.     if (IndexToFormat(hWnd, &FileInfoFirst, nSelection)
  2186.     == 0)
  2187. PostMessage(hWnd, WM_CLOSE, 0, 0);
  2188.     }
  2189.     break;
  2190. case ID_CANCEL:                 
  2191.     PostMessage(hWnd, WM_CLOSE, 0, 0);
  2192.     break;
  2193. case ID_APPLY:                  
  2194.     if ((nSelection = SendMessage(hWndFormats_LB,
  2195. LB_GETCURSEL, 0, 0)) != LB_ERR)
  2196.     IndexToFormat(hWnd, &FileInfoFirst, nSelection);
  2197.     break;
  2198. default:
  2199.     break;
  2200. }
  2201. break;
  2202.     case WM_CLOSE:
  2203. EndDialog(hWnd, 0);
  2204. break;
  2205.     default:
  2206. return(0);
  2207. break;               
  2208.     }
  2209.     return(1);
  2210. }
  2211. // =======================================================================
  2212. /*  This routine will determine the output format in
  2213.     terms of an integer from the
  2214.     current output rate, type, etc.
  2215.     stored in the direct sound routines.   Integer
  2216.     values designate the string # in rgszTypes,
  2217.     i.e. index 0 is 8000kHz, 8 bit mono, 
  2218.     etc...
  2219.     Input:
  2220. hWnd    - Handle of the current window.
  2221. pFileInfo   - Pointer to the file info to retrieve the format for.
  2222.     Output:
  2223. The index of the format, LB_ERR if undetermined.
  2224. */
  2225. // =======================================================================
  2226. int FormatToIndex(HWND hWnd, FILEINFO *pFileInfo)
  2227. {
  2228.     WAVEFORMATEX    wfx;
  2229.     DWORD       dwWaveStyle;
  2230.     DWORD       dwSize;
  2231.     int         nError              = 0;
  2232.     // Get the format.
  2233.     if ((nError = pFileInfo->pDSB->lpVtbl->GetFormat(pFileInfo->pDSB,
  2234.     &wfx, sizeof(wfx), &dwSize)) != 0)
  2235.     {
  2236.     goto ERROR_IN_ROUTINE;
  2237.     }
  2238.     if( dwSize > sizeof( wfx ) ) {
  2239.     nError = DSERR_GENERIC;
  2240.     goto ERROR_IN_ROUTINE;
  2241.     }
  2242.     // Change wfx to an integer.
  2243.     // Assume theres an error and check all parameters to 
  2244.     // see if its valid.
  2245.     nError = LB_ERR;
  2246.     dwWaveStyle = 0;
  2247.     if (wfx.wFormatTag != WAVE_FORMAT_PCM)
  2248.    goto ERROR_IN_ROUTINE;
  2249.     // Check the channels
  2250. switch (wfx.nChannels)
  2251. {
  2252. case 1:
  2253. break;
  2254. case 2:
  2255.     dwWaveStyle |= 1;
  2256. break;
  2257.     default:
  2258. goto ERROR_IN_ROUTINE;
  2259. }
  2260.     // Check the bits...
  2261. switch (wfx.wBitsPerSample)
  2262. {
  2263. case 8:
  2264. break;
  2265. case 16:
  2266. dwWaveStyle |= 2;
  2267. break;
  2268.     default:
  2269. goto ERROR_IN_ROUTINE;
  2270.     }
  2271.     // Check the rate.
  2272. switch(wfx.nSamplesPerSec)
  2273. {
  2274. case 8000:
  2275. break;
  2276. case 11025:
  2277.     dwWaveStyle |= 4;
  2278. break;
  2279. case 22050:
  2280.     dwWaveStyle |= 8;
  2281. break;
  2282. case 44100:
  2283.     dwWaveStyle |= 12;
  2284. break;
  2285.     default:
  2286. goto ERROR_IN_ROUTINE;
  2287.     }
  2288.     nError = (int)dwWaveStyle;
  2289. ERROR_IN_ROUTINE:
  2290.     return(nError);
  2291. }
  2292. // =======================================================================
  2293. /*  This will convert an index (from a list box for instance)
  2294.     to a format by passing
  2295.     in the format to direct sound.
  2296.     Input:
  2297. hWnd        -   Handle to window.
  2298. pFileInfo   -   Pointer to current file info.
  2299. index       -   Index value to convert to a
  2300.     waveformat structure.
  2301.     Output:
  2302. 0 if successful, else the error code.
  2303. */
  2304. // =======================================================================
  2305. int IndexToFormat(HWND hWnd, FILEINFO *pFileInfo, int index)
  2306. {
  2307.     int         nError      = 0;
  2308.     pFileInfo->pwfx->wFormatTag = WAVE_FORMAT_PCM;
  2309.     pFileInfo->pwfx->nChannels = 2;                                     // Assume stereo.
  2310.     if ((index%2) == 0)
  2311.     pFileInfo->pwfx->nChannels = 1;                                 // Its mono.
  2312.     // Assume 16 bit    
  2313.     pFileInfo->pwfx->nBlockAlign = 2*pFileInfo->pwfx->nChannels;
  2314.     pFileInfo->pwfx->wBitsPerSample = 16;
  2315.     if ((index%4) < 2) {
  2316.     // Its 8 bit.
  2317.     pFileInfo->pwfx->nBlockAlign = 1*pFileInfo->pwfx->nChannels;
  2318.     pFileInfo->pwfx->wBitsPerSample = 8;
  2319.     }
  2320.     
  2321.     pFileInfo->pwfx->nSamplesPerSec = 44100;    // Assume 44.1 kHz
  2322.     if (index < 4)
  2323. pFileInfo->pwfx->nSamplesPerSec = 8000;
  2324.     else if (index < 8)
  2325. pFileInfo->pwfx->nSamplesPerSec = 11025;
  2326.     else if (index < 12)
  2327. pFileInfo->pwfx->nSamplesPerSec = 22050;
  2328.     
  2329.     
  2330.     pFileInfo->pwfx->nAvgBytesPerSec = pFileInfo->pwfx->nSamplesPerSec *
  2331.        pFileInfo->pwfx->nBlockAlign;                                        
  2332.     pFileInfo->pwfx->cbSize = 0;
  2333.     if ((nError = pFileInfo->pDSB->lpVtbl->SetFormat(pFileInfo->pDSB,
  2334. pFileInfo->pwfx)) != DS_OK)         {
  2335. MessageBox(hWnd, "Cannot set format buffer",
  2336.    "Direct Sound Error", MB_OK);
  2337.     goto ERROR_DONE_ROUTINE;
  2338.     }
  2339. ERROR_DONE_ROUTINE:
  2340.     return(nError);
  2341. }
  2342. // =======================================================================
  2343. /* GetMediaStartPath()                                                      */
  2344. /*                                                                          */
  2345. /*   This helper function attempts to get the media directory for Direct3D, */
  2346. /* which is where all the installed DX wave files go. If it can't find that */
  2347. /* it settles for the media sub-directory of the Windows directory.         */
  2348. // =======================================================================
  2349. void GetMediaStartPath( void )
  2350.     {
  2351.     HKEY    hReg;
  2352.     DWORD   cbStartPathLen;
  2353.     if( ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  2354. gszRegKeyDirect3D,
  2355. 0, KEY_READ, &hReg ))
  2356. {
  2357.         goto REG_OPEN_FAILED;
  2358. }
  2359.     else
  2360. {
  2361. // Query the Registry for the path to the media directory
  2362. cbStartPathLen = sizeof( gszCDStartPath );
  2363. if( ERROR_SUCCESS != RegQueryValueEx( hReg, gszRegValueD3DPath,
  2364. NULL, NULL,
  2365. gszCDStartPath, &cbStartPathLen ))
  2366.     {
  2367.     goto REG_OPEN_FAILED;
  2368.     }
  2369. RegCloseKey( hReg );
  2370. hReg = NULL;
  2371. }
  2372.     return;
  2373. REG_OPEN_FAILED:
  2374.     // Start off by getting the Windows directory -- we're trying to build a
  2375.     // file path like "C:WINDOWSMEDIA", but the WINDOWS directory could be
  2376.     // named anything, so we must ask.
  2377.     GetWindowsDirectory( gszCDStartPath, sizeof(gszCDStartPath));
  2378.     // If there's no trailing backslash, append one
  2379.     if( lstrcmp( &gszCDStartPath[lstrlen(gszCDStartPath)], TEXT("\") ))
  2380. lstrcat( gszCDStartPath, TEXT("\"));
  2381.     // Now add on the MEDIA part of the path
  2382.     lstrcat( gszCDStartPath, TEXT("MEDIA"));
  2383.     }
  2384. // =======================================================================
  2385. // fGetToken()
  2386. //
  2387. //    Parses the command-line string "in place" starting at pszStart.  A ptr
  2388. // to the start of the next token and it's length will be the out parameters,
  2389. // or NULL and 0 if no token.  Note that *ppszRet will NOT be NULL-terminated
  2390. // since the string is part of another string.  That's what then length is for.
  2391. //
  2392. // Returns: TRUE if a token was retrieved, or FALSE if there was no token.
  2393. // =======================================================================
  2394. BOOL fGetToken( PSTR pszStart, PSTR *ppszRet, int *pcchRet )
  2395.     {
  2396.     PSTR  pszCur = pszStart;
  2397.     PSTR  pszTokStart;
  2398.     if( !pszStart || NULL == ppszRet || NULL == pcchRet )
  2399. return FALSE;
  2400.     // Skip leading whitespace
  2401.     while( *pszCur && (*pszCur == ' ' || *pszCur == 't'))
  2402. pszCur++;
  2403.     *ppszRet = NULL;
  2404.     *pcchRet = 0;
  2405.     if( *pszCur )
  2406. {
  2407. pszTokStart = pszCur;
  2408. while( *pszCur && *pszCur != ' ' && *pszCur != 't' )
  2409.     pszCur++;
  2410. *ppszRet = pszTokStart;
  2411. *pcchRet = (int)(pszCur - pszTokStart);
  2412. }
  2413.     if( *pcchRet != 0 )
  2414. return TRUE;
  2415.     else
  2416. return FALSE;
  2417.     }
  2418. // =======================================================================
  2419. // fMatchToken()
  2420. //
  2421. //    Attempts to match the first cchLen characters of pszDatum to the
  2422. // string at pszString.  The comparison is case-insensitive (this function
  2423. // is designed for command-line switch matching).
  2424. //
  2425. // Returns: TRUE if the first cchLen characters are a match, else FALSE.
  2426. // =======================================================================
  2427. BOOL fMatchToken( PSTR pszString, PSTR pszDatum, int cchLen )
  2428.     {
  2429.     int i;
  2430.     for( i = 0; i < cchLen; i++ )
  2431. {
  2432. if( CharLower( (LPTSTR)MAKELONG( pszString[i], 0 ))
  2433.     != CharLower( (LPTSTR)MAKELONG( pszDatum[i], 0 )))
  2434.     return FALSE;
  2435. }
  2436.     return TRUE;
  2437.     }
  2438. // =======================================================================
  2439. // ParseCommandLine()
  2440. //
  2441. //    Given a command-line string without the module name, this function will
  2442. // parse the command line and takes action on whatever it finds there.
  2443. //
  2444. // Returns: TRUE if successful, or FALSE if there was an error.
  2445. // =======================================================================
  2446. BOOL ParseCommandLine(LPSTR lpszCmdLine)
  2447.     {
  2448.     PSTR pszCur,pszToken;
  2449.     PSTR ppszFiles[MAXCONTROLS];
  2450.     BOOL fStartPlaying = FALSE, fStartLooping = FALSE;
  2451.     int cchTokLen = 0, i, nFilesFound;
  2452.     pszCur = lpszCmdLine;
  2453.     // First get all the command line switches
  2454.     while( fGetToken(pszCur, &pszToken, &cchTokLen) &&
  2455.    (pszToken[0] == '/' || pszToken[0] == '-' ))
  2456. {
  2457. pszCur = pszToken + cchTokLen;
  2458. pszToken++;
  2459. if( fMatchToken( pszToken, "PLAY", 4 ))
  2460.     {
  2461.     fStartPlaying = TRUE;
  2462.     }
  2463. else if( fMatchToken( pszToken, "LOOP", 4 ))
  2464.     {
  2465.     fStartLooping = TRUE;
  2466.     }
  2467. else
  2468.     {
  2469.     // We don't recognize this mysterious switch, so eat it and move on
  2470.     }
  2471. }
  2472.     // Anything left on the command-line will be treated as a filename and
  2473.     // we'll attempt to open it after we've found them all
  2474.     nFilesFound = 0;
  2475.     while( fGetToken(pszCur, &pszToken, &cchTokLen) && nFilesFound < MAXCONTROLS )
  2476. {
  2477. pszCur = pszToken + cchTokLen;
  2478. ppszFiles[nFilesFound] = GlobalAllocPtr( GPTR, (cchTokLen+1)*sizeof(char));
  2479. // Copy the token out of the command-line string and into our buffer
  2480. CopyMemory( ppszFiles[nFilesFound], pszToken, cchTokLen*sizeof(char));
  2481. // Append a NULL terminator to what we just copied (to be safe)
  2482. *(ppszFiles[nFilesFound] + cchTokLen) = 0;
  2483. nFilesFound++;
  2484. }
  2485.     // This function will take the array of strings we've created and open
  2486.     // each string as a file.  It will obey the global fStartPlaying and
  2487.     // fStartLooping flags we may have already set above
  2488.     if( nFilesFound )
  2489. BatchOpenFiles( ppszFiles, nFilesFound, fStartPlaying, fStartLooping );
  2490.     // Free the space we allocated
  2491.     for( i = 0; i < nFilesFound; i++ )
  2492. {
  2493. GlobalFreePtr( ppszFiles[i] );
  2494. ppszFiles[i] = NULL;
  2495. }
  2496.     // Returning TRUE means the caller should continue doing what they
  2497.     // were doing: we succeeded.
  2498.     return TRUE;
  2499.     }
  2500. // =======================================================================
  2501. // BatchOpenFiles()
  2502. //
  2503. //    Takes an array of string pointers and tries to open each as a file to
  2504. // playback.  If fPlay is TRUE, the files will be played as they are being
  2505. // opened.  If fLoop is TRUE, they will also be set to loop.
  2506. //
  2507. // Returns: FALSE in the event of catastrophic failure, otherwise TRUE.
  2508. // =======================================================================
  2509. BOOL BatchOpenFiles( PSTR *ppszFiles, int nFiles, BOOL fPlay, BOOL fLoop )
  2510.     {
  2511.     int i;
  2512.     FILEINFO *pfi;
  2513.     DWORD cSamples;
  2514.     // Cap the number of files we can load out of the given set if we'd load
  2515.     // too many otherwise
  2516.     if( GetNumControls(&FileInfoFirst) + nFiles > MAXCONTROLS )
  2517. nFiles = MAXCONTROLS - GetNumControls(&FileInfoFirst);
  2518.     for( i = 0; i < nFiles; i++ )
  2519. {
  2520. if(( pfi = GlobalAllocPtr(GPTR, sizeof(FILEINFO))) == NULL )
  2521.     goto BOF_Fail;
  2522. ZeroMemory( pfi, sizeof(FILEINFO));
  2523. strcpy( pfi->szFileName, ppszFiles[i] );
  2524. if( WaveLoadFile( ppszFiles[i], &pfi->cbSize, &cSamples,
  2525.   &pfi->pwfx, &pfi->pbData ) != 0 )
  2526.     goto BOF_LoopError;
  2527. GetNextControlCoords( &FileInfoFirst, &pfi->cox, &pfi->coy );
  2528. if( NewDirectSoundBuffer(pfi) != 0)
  2529.     goto BOF_LoopError;
  2530. Assert( pfi->pbData != NULL );
  2531. if( AddToList( &FileInfoFirst, pfi ) != 0 )
  2532.     goto BOF_LoopError;
  2533. pfi->nFileName = 0;
  2534. if( CreateControl( hWndMain, pfi, pfi->pwfx->nSamplesPerSec,
  2535.        (MAXPAN_TB-MINPAN_TB)/2, MINVOL_TB ) != 0 )
  2536.     {
  2537.     ReleaseDirectSoundBuffer(pfi);
  2538.     RemoveFromList( pfi, &FileInfoFirst );
  2539.     // RemoveFromList will do all the cleanup
  2540.     pfi = NULL;
  2541.     goto BOF_LoopError;
  2542.     }
  2543. ChangeOutputVol(pfi);
  2544. ChangeOutputFreq(pfi);
  2545. ChangeOutputPan(pfi);
  2546. // LOOP is only obeyed if PLAY was also specified
  2547. if( fPlay )
  2548.     {
  2549.     if( fLoop )
  2550. {
  2551. pfi->fLooped = TRUE;
  2552. SendMessage( pfi->hWndLooped_BN, BM_SETCHECK, TRUE, 0L );
  2553. }
  2554.     SendMessage( hWndMain, WM_COMMAND, 0, (LPARAM)pfi->hWndPlay_BN );
  2555.     }
  2556. // Avoid the in-loop error cleanup by using a continue statement here
  2557. // to jump back up to the top
  2558. continue;
  2559. // Cleanup code in case we fail to open a particular file -- we should
  2560. // just ignore this one and continue because we might still be able to
  2561. // open other files
  2562.     BOF_LoopError:
  2563. if( NULL != pfi )
  2564.     {
  2565.     if( NULL != pfi->pwfx )
  2566. {
  2567. GlobalFreePtr(pfi->pwfx);
  2568. pfi->pwfx = NULL;
  2569. }
  2570.     if( NULL != pfi->pbData )
  2571. {
  2572. GlobalFreePtr(pfi->pbData);
  2573. pfi->pbData = NULL;
  2574. }
  2575.     ReleaseDirectSoundBuffer(pfi);
  2576.     GlobalFreePtr(pfi);
  2577.     pfi = NULL;
  2578.     }
  2579. }
  2580.     UpdateMainStatus();
  2581.     return TRUE;
  2582. BOF_Fail:
  2583.     return FALSE;
  2584.     }