home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / directx2 / sdk / samples / dsshow / shell.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-05-28  |  67.2 KB  |  2,806 lines

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