home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / acmapp / aaplyrec.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  33KB  |  1,311 lines

  1. //==========================================================================;
  2. //
  3. //  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  4. //  KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  5. //  IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  6. //  PURPOSE.
  7. //
  8. //  Copyright (C) 1992 - 1997 Microsoft Corporation.  All Rights Reserved.
  9. //
  10. //--------------------------------------------------------------------------;
  11. //
  12. //  aaplyrec.c
  13. //
  14. //  Description:
  15. //      An play/record dialog based on MCI Wave.
  16. //
  17. //
  18. //  Known Bugs In MCIWAVE for Windows 3.1:
  19. //  ======================================
  20. //
  21. //  o   If you are running SHARE (or the equivelant) and attempt to open
  22. //      a file that is open by another application, you will receive the
  23. //      following error:
  24. //
  25. //          "Cannot find the specified file. Make sure the path and
  26. //           filename are correct..."
  27. //
  28. //      This is of course wrong. The problem is the file cannot be opened
  29. //      read/write by multiple applications.
  30. //
  31. //  o   Opening a wave file that is more than about three seconds long and
  32. //      issueing the following commands will hang Windows:
  33. //
  34. //          open xxx.wav alias zyz          ; open > 3 second file
  35. //          delete zyz from 1000 to 2000    ; remove some data
  36. //          delete zyz from 1000 to 2000    ; do it again and you hang
  37. //
  38. //      I think this will also happen with the following commands:
  39. //
  40. //          open c:\win31\ding.wav alias zyz
  41. //          delete zyz to 100
  42. //
  43. //  o   You cannot play or record data with a synchronous wave device. This
  44. //      is due to MCIWAVE relying on the ability to 'stream' data. This is
  45. //      not really a bug, just a limitation.
  46. //
  47. //  o   Block alignment is not correctly handled for non-PCM wave files
  48. //      when editing (includes recording). It is illegal to start recording
  49. //      in the middle of a block. The result if this happens is garbage
  50. //      data. This occurs if you insert data with a partial block at the
  51. //      end also...
  52. //
  53. //  o   It is possible to kill Windows by issueing the following commands
  54. //      without yielding between sending the commands:
  55. //
  56. //          capability <file> inputs
  57. //          close <file>
  58. //          open <file>
  59. //
  60. //      Should be able to fix the problem by Yield'ing.
  61. //
  62. //  o   Saving to the same wave file twice without closing the device deletes
  63. //      the existing file. Don't save twice.
  64. //  
  65. //  o   Saving an 'empty' wave file does not work. Issueing the following
  66. //      commands demonstrates the problem:
  67. //
  68. //          open new type waveaudio alias zyz
  69. //          save zyz as c:\zyz.wav
  70. //
  71. //      You will receive an 'out of memory error' which is completely bogus.
  72. //      Just don't save empty files.
  73. //
  74. //  o   Setting the time format to bytes doesn't work with compressed files.
  75. //      Sigh...
  76. //
  77. //  o   And there are others with less frequently used commands.
  78. //
  79. //==========================================================================;
  80.  
  81. #include <windows.h>
  82. #include <windowsx.h>
  83. #include <mmsystem.h>
  84. #include <stdlib.h>
  85. #include <memory.h>
  86. #include <mmreg.h>
  87. #include <msacm.h>
  88.  
  89. #include "muldiv32.h"
  90. #include "appport.h"
  91. #include "acmapp.h"
  92.  
  93. #include "debug.h"
  94.  
  95.  
  96. #ifndef _MCIERROR_
  97. #define _MCIERROR_
  98. typedef DWORD           MCIERROR;   // error return code, 0 means no error
  99. #endif
  100.  
  101.  
  102. TCHAR           gszAlias[]          = TEXT("zyzthing");
  103.  
  104. BOOL            gfFileOpen;
  105. BOOL            gfDirty;
  106. BOOL            gfTimerGoing;
  107.  
  108. UINT            guPlayRecordStatus;
  109.  
  110.  
  111. #define AAPLAYRECORD_TIMER_RESOLUTION       54
  112.  
  113. #define AAPLAYRECORD_MAX_MCI_COMMAND_CHARS  255
  114.  
  115. #define AAPLAYRECORD_STATUS_NOT_READY       0
  116. #define AAPLAYRECORD_STATUS_PAUSED          1
  117. #define AAPLAYRECORD_STATUS_PLAYING         2
  118. #define AAPLAYRECORD_STATUS_STOPPED         3
  119. #define AAPLAYRECORD_STATUS_RECORDING       4
  120. #define AAPLAYRECORD_STATUS_SEEKING         5
  121.  
  122. #define AAPLAYRECORD_STATUS_NOT_OPEN        (UINT)-1
  123.  
  124.  
  125. //--------------------------------------------------------------------------;
  126. //  
  127. //  MCIERROR AcmPlayRecordSendCommand
  128. //  
  129. //  Description:
  130. //      The string is of the form "verb params" our device name is inserted
  131. //      after the verb and send to the device.
  132. //  
  133. //  Arguments:
  134. //      HWND hwnd:
  135. //  
  136. //      PSTR pszCommand:
  137. //  
  138. //      PSTR pszReturn:
  139. //  
  140. //      UINT cbReturn:
  141. //  
  142. //      BOOL fErrorBox:
  143. //  
  144. //  Return (MCIERROR):
  145. //  
  146. //  
  147. //--------------------------------------------------------------------------;
  148.  
  149. MCIERROR FNLOCAL AcmPlayRecordSendCommand
  150. (
  151.     HWND                    hwnd,
  152.     PTSTR                   pszCommand,
  153.     PTSTR                   pszReturn,
  154.     UINT                    cbReturn,
  155.     BOOL                    fErrorBox
  156. )
  157. {
  158.     MCIERROR            mcierr;
  159.     TCHAR               ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS * 2];
  160.     TCHAR              *pch;
  161.     PTSTR               psz;
  162.  
  163.     pch = pszCommand;
  164.  
  165.     while (('\t' == *pch) || (' ' == *pch))
  166.     {
  167.         pch++;
  168.     }
  169.  
  170.     if (0 == lstrlen(pch))
  171.     {
  172.         return (MMSYSERR_NOERROR);
  173.     }
  174.  
  175.     pch = ach;
  176.     psz = pszCommand;
  177.     while (('\0' != *psz) && (' ' != *psz))
  178.     {
  179.         *pch++ = *psz++;
  180.     }
  181.  
  182.     *pch++ = ' ';
  183.  
  184.     lstrcpy(pch, gszAlias);
  185.     lstrcat(pch, psz);
  186.  
  187.     mcierr = mciSendString(ach, pszReturn, cbReturn, hwnd);
  188.     if (MMSYSERR_NOERROR != mcierr)
  189.     {
  190.         if (fErrorBox)
  191.         {
  192.             int         n;
  193.  
  194.             n = wsprintf(ach, TEXT("Command: '%s'\n\nMCI Wave Error (%lu): "),
  195.                             (LPTSTR)pszCommand, mcierr);
  196.  
  197.             mciGetErrorString(mcierr, &ach[n], SIZEOF(ach) - n);
  198.             MessageBox(hwnd, ach, TEXT("MCI Wave Error"), MB_ICONEXCLAMATION | MB_OK);
  199.         }
  200.     }
  201.  
  202.     return (mcierr);
  203. } // AcmPlayRecordSendCommand()
  204.  
  205.  
  206. //--------------------------------------------------------------------------;
  207. //  
  208. //  BOOL AcmAppPlayRecordCommand
  209. //  
  210. //  Description:
  211. //  
  212. //  
  213. //  Arguments:
  214. //      HWND hwnd:
  215. //  
  216. //  Return (BOOL):
  217. //  
  218. //  
  219. //--------------------------------------------------------------------------;
  220.  
  221. BOOL FNLOCAL AcmAppPlayRecordCommand
  222. (
  223.     HWND                    hwnd
  224. )
  225. {
  226.     TCHAR               ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS * 2];
  227.     HWND                hedit;
  228.     MCIERROR            mcierr;
  229.  
  230.     //
  231.     //
  232.     //
  233.     hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_COMMAND);
  234.     Edit_SetSel(hedit, 0, -1);
  235.  
  236.     Edit_GetText(hedit, ach, SIZEOF(ach));
  237.  
  238.     mcierr = AcmPlayRecordSendCommand(hwnd, ach, ach, SIZEOF(ach), FALSE);
  239.     if (MMSYSERR_NOERROR != mcierr)
  240.     {
  241.         mciGetErrorString(mcierr, ach, SIZEOF(ach));
  242.     }
  243.  
  244.     hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_RESULT);
  245.     Edit_SetText(hedit, ach);
  246.  
  247.     return (TRUE);
  248. } // AcmAppPlayRecordCommand()
  249.  
  250.  
  251. //--------------------------------------------------------------------------;
  252. //  
  253. //  BOOL AcmAppPlayRecordSetPosition
  254. //  
  255. //  Description:
  256. //  
  257. //  
  258. //  Arguments:
  259. //      HWND hwnd:
  260. //  
  261. //      HWND hsb:
  262. //  
  263. //      UINT uCode:
  264. //  
  265. //      int nPos:
  266. //  
  267. //  Return (BOOL):
  268. //  
  269. //  
  270. //--------------------------------------------------------------------------;
  271.  
  272. BOOL FNLOCAL AcmAppPlayRecordSetPosition
  273. (
  274.     HWND                    hwnd,
  275.     HWND                    hsb,
  276.     UINT                    uCode,
  277.     int                     nPos
  278. )
  279. {
  280.     MCIERROR            mcierr;
  281.     TCHAR               szPosition[40];
  282.     TCHAR               szLength[40];
  283.     LONG                lLength;
  284.     LONG                lPosition;
  285.     LONG                lPageInc;
  286.     int                 nRange;
  287.     int                 nMinPos;
  288.  
  289.  
  290.     //
  291.     //
  292.     //
  293.     //
  294.     if (AAPLAYRECORD_STATUS_NOT_OPEN == guPlayRecordStatus)
  295.     {
  296.         return (FALSE);
  297.     }
  298.  
  299.  
  300.     //
  301.     //
  302.     //
  303.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status length"), szLength, SIZEOF(szLength), FALSE);
  304.     if (MMSYSERR_NOERROR != mcierr)
  305.     {
  306.         return (FALSE);
  307.     }
  308.  
  309.     lLength = _tcstol(szLength, NULL, 10);
  310.     if (0L == lLength)
  311.     {
  312.         return (FALSE);
  313.     }
  314.  
  315.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status position"), szPosition, SIZEOF(szPosition), FALSE);
  316.     if (MMSYSERR_NOERROR != mcierr)
  317.     {
  318.         return (FALSE);
  319.     }
  320.  
  321.     lPosition = _tcstol(szPosition, NULL, 10);
  322.  
  323.     lPageInc = (lLength / 10);
  324.     if (0L == lPageInc)
  325.     {
  326.         lPageInc = 1;
  327.     }
  328.  
  329.  
  330.     //
  331.     //
  332.     //
  333.     switch (uCode)
  334.     {
  335.         case SB_PAGEDOWN:
  336.             lPosition = min(lLength, lPosition + lPageInc);
  337.             break;
  338.  
  339.         case SB_LINEDOWN:
  340.             lPosition = min(lLength, lPosition + 1);
  341.             break;
  342.  
  343.         case SB_PAGEUP:
  344.             lPosition -= lPageInc;
  345.  
  346.             //-- fall through --//
  347.  
  348.         case SB_LINEUP:
  349.             lPosition = (lPosition < 1) ? 0 : (lPosition - 1);
  350.             break;
  351.  
  352.  
  353.         case SB_TOP:
  354.             lPosition = 0;
  355.             break;
  356.  
  357.         case SB_BOTTOM:
  358.             lPosition = lLength;
  359.             break;
  360.  
  361.         case SB_THUMBPOSITION:
  362.         case SB_THUMBTRACK:
  363.             GetScrollRange(hsb, SB_CTL, &nMinPos, &nRange);
  364.             lPosition = (DWORD)MulDivRN((DWORD)nPos, (DWORD)lLength, (DWORD)nRange);
  365.             break;
  366.  
  367.         default:
  368.             return (FALSE);
  369.     }
  370.  
  371.     //
  372.     //
  373.     //
  374.     wsprintf(szPosition, TEXT("seek to %lu"), lPosition);
  375.     AcmPlayRecordSendCommand(hwnd, szPosition, NULL, 0, FALSE);
  376.  
  377.     return (TRUE);
  378. } // AcmAppPlayRecordSetPosition()
  379.  
  380.  
  381. //--------------------------------------------------------------------------;
  382. //  
  383. //  BOOL AcmAppPlayRecordStatus
  384. //  
  385. //  Description:
  386. //  
  387. //  
  388. //  Arguments:
  389. //      HWND hwnd:
  390. //  
  391. //      PACMAPPFILEDESC paafd:
  392. //  
  393. //  Return (BOOL):
  394. //  
  395. //  
  396. //--------------------------------------------------------------------------;
  397.  
  398. BOOL FNLOCAL AcmAppPlayRecordStatus
  399. (
  400.     HWND                    hwnd,
  401.     PACMAPPFILEDESC         paafd
  402. )
  403. {
  404.     TCHAR               ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS];
  405.     TCHAR               szMode[40];
  406.     TCHAR               szPosition[40];
  407.     TCHAR               szLength[40];
  408.     TCHAR               szFormat[40];
  409.     MCIERROR            mcierr;
  410.     UINT                uStatus;
  411.     BOOL                fStartTimer;
  412.     BOOL                fPlay;
  413.     BOOL                fPause;
  414.     BOOL                fStop;
  415.     BOOL                fStart;
  416.     BOOL                fEnd;
  417.     BOOL                fRecord;
  418.     BOOL                fCommand;
  419.     UINT                uIdFocus;
  420.     DWORD               dwLength;
  421.     DWORD               dwPosition;
  422.     HWND                hsb;
  423.  
  424.     //
  425.     //
  426.     //
  427.     if (AAPLAYRECORD_STATUS_NOT_OPEN != guPlayRecordStatus)
  428.     {
  429.         mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status mode"), szMode, SIZEOF(szMode), FALSE);
  430.         if (MMSYSERR_NOERROR != mcierr)
  431.         {
  432.             guPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN;
  433.         }
  434.     }
  435.  
  436.  
  437.     //
  438.     //  assume all buttons disabled
  439.     //
  440.     fStartTimer = FALSE;
  441.     fPlay       = FALSE;
  442.     fPause      = FALSE;
  443.     fStop       = FALSE;
  444.     fStart      = FALSE;
  445.     fEnd        = FALSE;
  446.     fRecord     = FALSE;
  447.     fCommand    = TRUE;
  448.     uIdFocus    = IDOK;
  449.     dwPosition  = 0L;
  450.     dwLength    = 0L;
  451.     lstrcpy(szFormat, TEXT("???"));
  452.  
  453.     hsb = GetDlgItem(hwnd, IDD_AAPLAYRECORD_SCROLL_POSITION);
  454.  
  455.  
  456.     //
  457.     //
  458.     //
  459.     if (AAPLAYRECORD_STATUS_NOT_OPEN == guPlayRecordStatus)
  460.     {
  461.         lstrcpy(szMode, TEXT("not open"));
  462.     }
  463.     else if (0 == lstrcmpi(TEXT("not ready"), szMode))
  464.     {
  465.         uStatus = AAPLAYRECORD_STATUS_NOT_READY;
  466.  
  467.         fStartTimer = TRUE;
  468.     }
  469.     else if (0 == lstrcmpi(TEXT("paused"), szMode))
  470.     {
  471.         uStatus = AAPLAYRECORD_STATUS_PAUSED;
  472.  
  473.         fPause      = TRUE;
  474.         fStop       = TRUE;
  475.     }
  476.     else if (0 == lstrcmpi(TEXT("playing"), szMode))
  477.     {
  478.         uStatus = AAPLAYRECORD_STATUS_PLAYING;
  479.  
  480.         fStartTimer = TRUE;
  481.         fPause      = TRUE;
  482.         fStop       = TRUE;
  483.     }
  484.     else if (0 == lstrcmpi(TEXT("stopped"), szMode))
  485.     {
  486.         uStatus = AAPLAYRECORD_STATUS_STOPPED;
  487.  
  488.         fPlay       = TRUE;
  489.         fStart      = TRUE;
  490.         fEnd        = TRUE;
  491.         fRecord     = TRUE;
  492.     }
  493.     else if (0 == lstrcmpi(TEXT("recording"), szMode))
  494.     {
  495.         uStatus = AAPLAYRECORD_STATUS_RECORDING;
  496.  
  497.         fStartTimer = TRUE;
  498.         fPause      = TRUE;
  499.         fStop       = TRUE;
  500.     }
  501.     else if (0 == lstrcmpi(TEXT("seeking"), szMode))
  502.     {
  503.         uStatus = AAPLAYRECORD_STATUS_SEEKING;
  504.  
  505.         fStartTimer = TRUE;
  506.         fStop       = TRUE;
  507.     }
  508.  
  509.  
  510.     //
  511.     //
  512.     //
  513.     //
  514.     //
  515.     if (fStartTimer)
  516.     {
  517.         if (!gfTimerGoing)
  518.         {
  519.             SetTimer(hwnd, 1, AAPLAYRECORD_TIMER_RESOLUTION, NULL);
  520.             gfTimerGoing = TRUE;
  521.         }
  522.     }
  523.     else if (gfTimerGoing)
  524.     {
  525.         KillTimer(hwnd, 1);
  526.         gfTimerGoing = FALSE;
  527.     }
  528.  
  529.  
  530.     //
  531.     //
  532.     //
  533.     //
  534.     if (AAPLAYRECORD_STATUS_NOT_OPEN != guPlayRecordStatus)
  535.     {
  536.         //
  537.         //
  538.         //
  539.         mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status position"), szPosition, SIZEOF(szPosition), FALSE);
  540.         if (MMSYSERR_NOERROR == mcierr)
  541.         {
  542.             dwPosition = _tcstoul(szPosition, NULL, 10);
  543.         }
  544.  
  545.         mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status length"), szLength, SIZEOF(szLength), FALSE);
  546.         if (MMSYSERR_NOERROR == mcierr)
  547.         {
  548.             dwLength   = _tcstoul(szLength, NULL, 10);
  549.         }
  550.  
  551.         mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status time format"), szFormat, SIZEOF(szFormat), FALSE);
  552.     }
  553.  
  554.  
  555.     //
  556.     //
  557.     //
  558.     //
  559.     if (uStatus != guPlayRecordStatus)
  560.     {
  561.         if (GetFocus() != hsb)
  562.         {
  563.             LRESULT             lr;
  564.  
  565.             lr = SendMessage(hwnd, DM_GETDEFID, 0, 0L);
  566.             if (DC_HASDEFID == HIWORD(lr))
  567.             {
  568.                 UINT        uIdDefId;
  569.  
  570.                 uIdDefId = LOWORD(lr);
  571.                 if (IDOK != uIdDefId)
  572.                 {
  573.                     HWND        hwndDefId;
  574.  
  575.                     hwndDefId = GetDlgItem(hwnd, uIdDefId);
  576.  
  577.                     Button_SetStyle(hwndDefId, BS_PUSHBUTTON, TRUE);
  578.                 }
  579.             }
  580.  
  581.  
  582.             SendMessage(hwnd, DM_SETDEFID, IDOK, 0L);
  583.  
  584.             SetFocus(GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_COMMAND));
  585.         }
  586.  
  587.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_PLAY),   fPlay  );
  588.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_PAUSE),  fPause );
  589.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_STOP),   fStop  );
  590.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_START),  fStart );
  591.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_END),    fEnd   );
  592.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_BTN_RECORD), fRecord);
  593.  
  594.         EnableWindow(GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_COMMAND), fCommand);
  595.         EnableWindow(GetDlgItem(hwnd, IDOK), fCommand);
  596.  
  597.         if (AAPLAYRECORD_STATUS_PAUSED == uStatus)
  598.             SetDlgItemText(hwnd, IDD_AAPLAYRECORD_BTN_PAUSE, TEXT("Resum&e"));
  599.         else
  600.             SetDlgItemText(hwnd, IDD_AAPLAYRECORD_BTN_PAUSE, TEXT("Paus&e"));
  601.  
  602.         guPlayRecordStatus = uStatus;
  603.     }
  604.  
  605.     //
  606.     //
  607.     //
  608.     AppFormatBigNumber(szPosition, dwPosition);
  609.     AppFormatBigNumber(szLength, dwLength);
  610.  
  611.     wsprintf(ach, TEXT("%s: %14s (%s) %s"),
  612.                  (LPSTR)szMode,
  613.                  (LPSTR)szPosition,
  614.                  (LPSTR)szLength,
  615.                  (LPSTR)szFormat);
  616.  
  617.     SetDlgItemText(hwnd, IDD_AAPLAYRECORD_TXT_POSITION, ach);
  618.  
  619.  
  620.     //
  621.     //
  622.     //
  623.     //
  624.     {
  625.         int         nRange;
  626.         int         nValue;
  627.         int         nMinPos;
  628.         int         nMaxPos;
  629.  
  630.         GetScrollRange(hsb, SB_CTL, &nMinPos, &nMaxPos);
  631.  
  632.         nRange = (int)min(dwLength, 32767L);
  633.  
  634.         if (nMaxPos != nRange)
  635.         {
  636.             SetScrollRange(hsb, SB_CTL, 0, nRange, FALSE);
  637.         }
  638.  
  639.         //
  640.         //
  641.         //
  642.         nValue = 0;
  643.         if (0L != dwLength)
  644.         {
  645.             nValue = (int)MulDivRN(dwPosition, nRange, dwLength);
  646.         }
  647.  
  648.         if (nValue != GetScrollPos(hsb, SB_CTL))
  649.         {
  650.             SetScrollPos(hsb, SB_CTL, nValue, TRUE);
  651.         }
  652.     }
  653.  
  654.     return (TRUE);
  655. } // AcmAppPlayRecordStatus()
  656.  
  657.  
  658.  
  659. //--------------------------------------------------------------------------;
  660. //  
  661. //  BOOL AcmAppPlayRecordRecord
  662. //  
  663. //  Description:
  664. //  
  665. //  
  666. //  Arguments:
  667. //      HWND hwnd:
  668. //  
  669. //      PACMAPPFILEDESC paafd:
  670. //  
  671. //  Return (BOOL):
  672. //  
  673. //  
  674. //--------------------------------------------------------------------------;
  675.  
  676. BOOL FNLOCAL AcmAppPlayRecordRecord
  677. (
  678.     HWND                    hwnd,
  679.     PACMAPPFILEDESC         paafd
  680. )
  681. {
  682.     MCIERROR            mcierr;
  683.  
  684.     //
  685.     //
  686.     //
  687.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("record insert"), NULL, 0, TRUE);
  688.     if (MMSYSERR_NOERROR == mcierr)
  689.     {
  690.         gfDirty = TRUE;
  691.     }
  692.  
  693.     return (MMSYSERR_NOERROR == mcierr);
  694. } // AcmAppPlayRecordRecord()
  695.  
  696.  
  697. //--------------------------------------------------------------------------;
  698. //  
  699. //  BOOL AcmAppPlayRecordStart
  700. //  
  701. //  Description:
  702. //  
  703. //  
  704. //  Arguments:
  705. //      HWND hwnd:
  706. //  
  707. //      PACMAPPFILEDESC paafd:
  708. //  
  709. //  Return (BOOL):
  710. //  
  711. //  
  712. //--------------------------------------------------------------------------;
  713.  
  714. BOOL FNLOCAL AcmAppPlayRecordStart
  715. (
  716.     HWND                    hwnd,
  717.     PACMAPPFILEDESC         paafd
  718. )
  719. {
  720.     MCIERROR            mcierr;
  721.  
  722.     //
  723.     //
  724.     //
  725.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("seek to start"), NULL, 0, TRUE);
  726.  
  727.     return (MMSYSERR_NOERROR == mcierr);
  728. } // AcmAppPlayRecordStart()
  729.  
  730.  
  731. //--------------------------------------------------------------------------;
  732. //  
  733. //  BOOL AcmAppPlayRecordEnd
  734. //  
  735. //  Description:
  736. //  
  737. //  
  738. //  Arguments:
  739. //      HWND hwnd:
  740. //  
  741. //      PACMAPPFILEDESC paafd:
  742. //  
  743. //  Return (BOOL):
  744. //  
  745. //  
  746. //--------------------------------------------------------------------------;
  747.  
  748. BOOL FNLOCAL AcmAppPlayRecordEnd
  749. (
  750.     HWND                    hwnd,
  751.     PACMAPPFILEDESC         paafd
  752. )
  753. {
  754.     MCIERROR            mcierr;
  755.  
  756.     //
  757.     //
  758.     //
  759.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("seek to end"), NULL, 0, TRUE);
  760.  
  761.     return (MMSYSERR_NOERROR == mcierr);
  762. } // AcmAppPlayRecordEnd()
  763.  
  764.  
  765. //--------------------------------------------------------------------------;
  766. //  
  767. //  BOOL AcmAppPlayRecordStop
  768. //  
  769. //  Description:
  770. //  
  771. //  
  772. //  Arguments:
  773. //      HWND hwnd:
  774. //  
  775. //      PACMAPPFILEDESC paafd:
  776. //  
  777. //  Return (BOOL):
  778. //  
  779. //  
  780. //--------------------------------------------------------------------------;
  781.  
  782. BOOL FNLOCAL AcmAppPlayRecordStop
  783. (
  784.     HWND                    hwnd,
  785.     PACMAPPFILEDESC         paafd
  786. )
  787. {
  788.     MCIERROR            mcierr;
  789.  
  790.     //
  791.     //
  792.     //
  793.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("stop"), NULL, 0, TRUE);
  794.  
  795.     return (MMSYSERR_NOERROR == mcierr);
  796. } // AcmAppPlayRecordStop()
  797.  
  798.  
  799. //--------------------------------------------------------------------------;
  800. //  
  801. //  BOOL AcmAppPlayRecordPause
  802. //  
  803. //  Description:
  804. //  
  805. //  
  806. //  Arguments:
  807. //      HWND hwnd:
  808. //  
  809. //      PACMAPPFILEDESC paafd:
  810. //  
  811. //  Return (BOOL):
  812. //  
  813. //  
  814. //--------------------------------------------------------------------------;
  815.  
  816. BOOL FNLOCAL AcmAppPlayRecordPause
  817. (
  818.     HWND                    hwnd,
  819.     PACMAPPFILEDESC         paafd
  820. )
  821. {
  822.     MCIERROR            mcierr;
  823.     PTSTR               psz;
  824.  
  825.     //
  826.     //
  827.     //
  828.     if (AAPLAYRECORD_STATUS_PAUSED == guPlayRecordStatus)
  829.         psz = TEXT("resume");
  830.     else
  831.         psz = TEXT("pause");
  832.  
  833.     mcierr = AcmPlayRecordSendCommand(hwnd, psz, NULL, 0, TRUE);
  834.  
  835.     return (MMSYSERR_NOERROR == mcierr);
  836. } // AcmAppPlayRecordPause()
  837.  
  838.  
  839. //--------------------------------------------------------------------------;
  840. //  
  841. //  BOOL AcmAppPlayRecordPlay
  842. //  
  843. //  Description:
  844. //  
  845. //  
  846. //  Arguments:
  847. //      HWND hwnd:
  848. //  
  849. //      PACMAPPFILEDESC paafd:
  850. //  
  851. //  Return (BOOL):
  852. //  
  853. //  
  854. //--------------------------------------------------------------------------;
  855.  
  856. BOOL FNLOCAL AcmAppPlayRecordPlay
  857. (
  858.     HWND                    hwnd,
  859.     PACMAPPFILEDESC         paafd
  860. )
  861. {
  862.     MCIERROR            mcierr;
  863.     TCHAR               szPosition[40];
  864.     TCHAR               szLength[40];
  865.  
  866.  
  867.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status position"), szPosition, SIZEOF(szPosition), TRUE);
  868.     if (MMSYSERR_NOERROR != mcierr)
  869.     {
  870.         return (FALSE);
  871.     }
  872.  
  873.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("status length"), szLength, SIZEOF(szLength), TRUE);
  874.     if (MMSYSERR_NOERROR != mcierr)
  875.     {
  876.         return (FALSE);
  877.     }
  878.  
  879.     if (0 == lstrcmp(szPosition, szLength))
  880.     {
  881.         AcmPlayRecordSendCommand(hwnd, TEXT("seek to start"), NULL, 0, TRUE);
  882.     }
  883.  
  884.  
  885.     //
  886.     //
  887.     //
  888.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("play"), NULL, 0, TRUE);
  889.  
  890.     return (MMSYSERR_NOERROR == mcierr);
  891. } // AcmAppPlayRecordPlay()
  892.  
  893.  
  894. //--------------------------------------------------------------------------;
  895. //  
  896. //  BOOL AcmAppPlayRecordClose
  897. //  
  898. //  Description:
  899. //  
  900. //  
  901. //  Arguments:
  902. //      HWND hwnd:
  903. //  
  904. //      PACMAPPFILEDESC paafd:
  905. //  
  906. //  Return (BOOL):
  907. //  
  908. //  
  909. //--------------------------------------------------------------------------;
  910.  
  911. BOOL FNLOCAL AcmAppPlayRecordClose
  912. (
  913.     HWND                    hwnd,
  914.     PACMAPPFILEDESC         paafd
  915. )
  916. {
  917.     MCIERROR            mcierr;
  918.  
  919.     if (gfDirty)
  920.     {
  921.         UINT    u;
  922.  
  923.         u = MessageBox(hwnd, TEXT("Save newly recorded data?"), TEXT("Save"),
  924.                        MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2);
  925.         if (IDYES == u)
  926.         {
  927.             AppHourGlass(TRUE);
  928.             mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("save"), NULL, 0, TRUE);
  929.             AppHourGlass(FALSE);
  930.         }
  931.         else
  932.         {
  933.             gfDirty = FALSE;
  934.         }
  935.     }
  936.  
  937.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("close"), NULL, 0, TRUE);
  938.  
  939.     return (MMSYSERR_NOERROR == mcierr);
  940. } // AcmAppPlayRecordClose()
  941.  
  942.  
  943. //--------------------------------------------------------------------------;
  944. //  
  945. //  BOOL AcmAppPlayRecordOpen
  946. //  
  947. //  Description:
  948. //  
  949. //  
  950. //  Arguments:
  951. //      HWND hwnd:
  952. //  
  953. //      PACMAPPFILEDESC paafd:
  954. //  
  955. //  Return (BOOL):
  956. //  
  957. //  
  958. //--------------------------------------------------------------------------;
  959.  
  960. BOOL FNLOCAL AcmAppPlayRecordOpen
  961. (
  962.     HWND                    hwnd,
  963.     PACMAPPFILEDESC         paafd,
  964.     UINT                    uWaveInId,
  965.     UINT                    uWaveOutId
  966. )
  967. {
  968.     TCHAR               ach[AAPLAYRECORD_MAX_MCI_COMMAND_CHARS];
  969.     MCIERROR            mcierr;
  970.  
  971.     guPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_OPEN;
  972.  
  973.     gfTimerGoing       = FALSE;
  974.     gfFileOpen         = FALSE;
  975.  
  976.     gfDirty = FALSE;
  977.  
  978.     if (NULL == paafd->pwfx)
  979.     {
  980.         MessageBox(hwnd, TEXT("No wave file currently selected."),
  981.                     TEXT("Open Error"), MB_ICONEXCLAMATION | MB_OK);
  982.         return (FALSE);
  983.     }
  984.  
  985.     wsprintf(ach, TEXT("open \"%s\" alias %s"), (LPSTR)paafd->szFilePath, (LPSTR)gszAlias);
  986.  
  987.     mcierr = mciSendString(ach, NULL, 0, NULL);
  988.     if (MMSYSERR_NOERROR != mcierr)
  989.     {
  990.         mciGetErrorString(mcierr, ach, SIZEOF(ach));
  991.         MessageBox(hwnd, ach, TEXT("Open Error"), MB_ICONEXCLAMATION | MB_OK);
  992.  
  993.         return (FALSE);
  994.     }
  995.  
  996.     gfFileOpen         = TRUE;
  997.     guPlayRecordStatus = AAPLAYRECORD_STATUS_NOT_READY;
  998.  
  999.     mcierr = AcmPlayRecordSendCommand(hwnd, TEXT("set time format samples"), NULL, 0, TRUE);
  1000.  
  1001.     if (WAVE_MAPPER != uWaveInId)
  1002.     {
  1003.         wsprintf(ach, TEXT("set input %u"), uWaveInId);
  1004.         mcierr = AcmPlayRecordSendCommand(hwnd, ach, NULL, 0, TRUE);
  1005.     }
  1006.  
  1007.     if (WAVE_MAPPER != uWaveOutId)
  1008.     {
  1009.         wsprintf(ach, TEXT("set output %u"), uWaveOutId);
  1010.         mcierr = AcmPlayRecordSendCommand(hwnd, ach, NULL, 0, TRUE);
  1011.     }
  1012.  
  1013.     return (TRUE);
  1014. } // AcmAppPlayRecordOpen()
  1015.  
  1016.  
  1017. //--------------------------------------------------------------------------;
  1018. //  
  1019. //  BOOL AcmAppPlayRecordInitCommands
  1020. //  
  1021. //  Description:
  1022. //  
  1023. //  
  1024. //  Arguments:
  1025. //      HWND hwnd:
  1026. //  
  1027. //      PACMAPPFILEDESC paafd:
  1028. //  
  1029. //  Return (BOOL):
  1030. //  
  1031. //  
  1032. //--------------------------------------------------------------------------;
  1033.  
  1034. BOOL FNLOCAL AcmAppPlayRecordInitCommands
  1035. (
  1036.     HWND                    hwnd,
  1037.     PACMAPPFILEDESC         paafd
  1038. )
  1039. {
  1040.     static PTSTR    pszCommands[] =
  1041.     {
  1042.         TEXT("play"),
  1043.         TEXT("play to Y"),
  1044.         TEXT("play from X to Y"),
  1045.  
  1046.         TEXT(""),
  1047.         TEXT("capability can eject"),
  1048.         TEXT("capability can play"),
  1049.         TEXT("capability can record"),
  1050.         TEXT("capability can save"),
  1051.         TEXT("capability compound device"),
  1052.         TEXT("capability device type"),
  1053.         TEXT("capability has audio"),
  1054.         TEXT("capability has video"),
  1055.         TEXT("capability inputs"),
  1056.         TEXT("capability outputs"),
  1057.         TEXT("capability uses files"),
  1058.  
  1059.         TEXT(""),
  1060.         TEXT("cue input !"),
  1061.         TEXT("cue output !"),
  1062.  
  1063.         TEXT(""),
  1064.         TEXT("delete to Y !"),
  1065.         TEXT("delete from X to Y !"),
  1066.  
  1067.         TEXT(""),
  1068.         TEXT("info input"),
  1069.         TEXT("info file"),
  1070.         TEXT("info output"),
  1071.         TEXT("info product"),
  1072.  
  1073.         TEXT(""),
  1074.         TEXT("pause"),
  1075.  
  1076.         TEXT(""),
  1077.         TEXT("record insert !"),
  1078.         TEXT("record overwrite !"),
  1079.         TEXT("record to Y !"),
  1080.         TEXT("record from X to Y !"),
  1081.  
  1082.         TEXT(""),
  1083.         TEXT("resume"),
  1084.  
  1085.         TEXT(""),
  1086.         TEXT("save"),
  1087.         TEXT("save FILENAME"),
  1088.  
  1089.         TEXT(""),
  1090.         TEXT("seek to Y"),
  1091.         TEXT("seek to start"),
  1092.         TEXT("seek to end"),
  1093.  
  1094.         TEXT(""),
  1095.         TEXT("set alignment X"),
  1096.         TEXT("set any input"),
  1097.         TEXT("set any output"),
  1098.         TEXT("set audio all off"),
  1099.         TEXT("set audio all on"),
  1100.         TEXT("set audio left off"),
  1101.         TEXT("set audio left on"),
  1102.         TEXT("set audio right off"),
  1103.         TEXT("set audio right on"),
  1104.         TEXT("set bitspersample X"),
  1105.         TEXT("set bytespersec X"),
  1106.         TEXT("set channels X"),
  1107.         TEXT("set format tag X"),
  1108.         TEXT("set format tag pcm"),
  1109.         TEXT("set input X"),
  1110.         TEXT("set output X"),
  1111.         TEXT("set samplespersec X"),
  1112.         TEXT("set time format bytes"),
  1113.         TEXT("set time format milliseconds"),
  1114.         TEXT("set time format samples"),
  1115.  
  1116.         TEXT(""),
  1117.         TEXT("status alignment"),
  1118.         TEXT("status bitspersample"),
  1119.         TEXT("status bytespersec"),
  1120.         TEXT("status channels"),
  1121.         TEXT("status current track"),
  1122.         TEXT("status format tag"),
  1123.         TEXT("status input"),
  1124.         TEXT("status length"),
  1125.         TEXT("status length track X"),
  1126.         TEXT("status level"),
  1127.         TEXT("status media present"),
  1128.         TEXT("status mode"),
  1129.         TEXT("status number of tracks"),
  1130.         TEXT("status output"),
  1131.         TEXT("status position"),
  1132.         TEXT("status position track X"),
  1133.         TEXT("status ready"),
  1134.         TEXT("status samplespersec"),
  1135.         TEXT("status start position"),
  1136.         TEXT("status time format"),
  1137.  
  1138.         TEXT(""),
  1139.         TEXT("stop"),
  1140.         NULL
  1141.     };
  1142.  
  1143.     HWND                hcb;
  1144.     UINT                u;
  1145.     PTSTR               psz;
  1146.  
  1147.     //
  1148.     //
  1149.     //
  1150.     hcb = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_COMMAND);
  1151.  
  1152.     for (u = 0; psz = pszCommands[u]; u++)
  1153.     {
  1154.         ComboBox_AddString(hcb, psz);
  1155.     }
  1156.  
  1157.     ComboBox_SetCurSel(hcb, 0);
  1158.  
  1159.     return (TRUE);
  1160. } // AcmAppPlayRecordInitCommands()
  1161.  
  1162.  
  1163.  
  1164. //--------------------------------------------------------------------------;
  1165. //
  1166. //  BOOL AcmAppPlayRecord
  1167. //
  1168. //  Description:
  1169. //
  1170. //
  1171. //  Arguments:
  1172. //      HWND hwnd: Handle to window.
  1173. //
  1174. //      UINT uMsg: Message being sent to the window.
  1175. //
  1176. //      WPARAM wParam: Specific argument to message.
  1177. //
  1178. //      LPARAM lParam: Specific argument to message.
  1179. //
  1180. //  Return (BOOL):
  1181. //      The return value is specific to the message that was received. For
  1182. //      the most part, it is FALSE if this dialog procedure does not handle
  1183. //      a message.
  1184. //
  1185. //
  1186. //--------------------------------------------------------------------------;
  1187.  
  1188. BOOL FNEXPORT AcmAppPlayRecord
  1189. (
  1190.     HWND                    hwnd,
  1191.     UINT                    uMsg,
  1192.     WPARAM                  wParam,
  1193.     LPARAM                  lParam
  1194. )
  1195. {
  1196.     PACMAPPFILEDESC     paafd;
  1197.     UINT                uId;
  1198.     HWND                hedit;
  1199.     HFONT               hfont;
  1200.  
  1201.     paafd = (PACMAPPFILEDESC)(UINT)GetWindowLong(hwnd, DWL_USER);
  1202.  
  1203.     switch (uMsg)
  1204.     {
  1205.         case WM_INITDIALOG:
  1206.             paafd = (PACMAPPFILEDESC)(UINT)lParam;
  1207.  
  1208.             SetWindowLong(hwnd, DWL_USER, lParam);
  1209.  
  1210. //          hfont = GetStockFont(ANSI_FIXED_FONT);
  1211.             hfont = ghfontApp;
  1212.  
  1213.             hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_TXT_POSITION);
  1214.             SetWindowFont(hedit, hfont, FALSE);
  1215.  
  1216.             hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_COMMAND);
  1217.             SetWindowFont(hedit, hfont, FALSE);
  1218.  
  1219.             hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_RESULT);
  1220.             SetWindowFont(hedit, hfont, FALSE);
  1221.  
  1222.             AcmAppPlayRecordInitCommands(hwnd, paafd);
  1223.  
  1224.             AcmAppPlayRecordOpen(hwnd, paafd, guWaveInId, guWaveOutId);
  1225.             AcmAppPlayRecordStatus(hwnd, paafd);
  1226.  
  1227.  
  1228.             //
  1229.             //  if the format is non-PCM, display a little warning so the
  1230.             //  user knows that not everything may work correctly when
  1231.             //  dealing working with MCI Wave..
  1232.             //
  1233.             if ((NULL != paafd->pwfx) &&
  1234.                 (WAVE_FORMAT_PCM != paafd->pwfx->wFormatTag))
  1235.             {
  1236.                 hedit = GetDlgItem(hwnd, IDD_AAPLAYRECORD_EDIT_RESULT);
  1237.                 Edit_SetText(hedit, TEXT("WARNING! There are known bugs with MCI Wave EDITING operations on non-PCM formats--see the README.TXT with this application. (end)\r\n\r\nRemember, DON'T PANIC!\r\n\r\n\r\n\r\n\r\n\r\n- zYz -"));
  1238.             }
  1239.             return (TRUE);
  1240.  
  1241.         case WM_TIMER:
  1242.             AcmAppPlayRecordStatus(hwnd, paafd);
  1243.             break;
  1244.  
  1245.         case WM_HSCROLL:
  1246.             HANDLE_WM_HSCROLL(hwnd, wParam, lParam, AcmAppPlayRecordSetPosition);
  1247.  
  1248.             guPlayRecordStatus = AAPLAYRECORD_STATUS_SEEKING;
  1249.             AcmAppPlayRecordStatus(hwnd, paafd);
  1250.             return (TRUE);
  1251.  
  1252.         case WM_COMMAND:
  1253.             uId = GET_WM_COMMAND_ID(wParam, lParam);
  1254.             switch (uId)
  1255.             {
  1256.                 case IDD_AAPLAYRECORD_BTN_PLAY:
  1257.                     AcmAppPlayRecordPlay(hwnd, paafd);
  1258.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1259.                     break;
  1260.  
  1261.                 case IDD_AAPLAYRECORD_BTN_PAUSE:
  1262.                     AcmAppPlayRecordPause(hwnd, paafd);
  1263.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1264.                     break;
  1265.  
  1266.                 case IDD_AAPLAYRECORD_BTN_STOP:
  1267.                     AcmAppPlayRecordStop(hwnd, paafd);
  1268.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1269.                     break;
  1270.  
  1271.                 case IDD_AAPLAYRECORD_BTN_START:
  1272.                     AcmAppPlayRecordStart(hwnd, paafd);
  1273.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1274.                     break;
  1275.  
  1276.                 case IDD_AAPLAYRECORD_BTN_END:
  1277.                     AcmAppPlayRecordEnd(hwnd, paafd);
  1278.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1279.                     break;
  1280.  
  1281.                 case IDD_AAPLAYRECORD_BTN_RECORD:
  1282.                     AcmAppPlayRecordRecord(hwnd, paafd);
  1283.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1284.                     break;
  1285.  
  1286.                 case IDOK:
  1287.                     AcmAppPlayRecordCommand(hwnd);
  1288.  
  1289.                     guPlayRecordStatus = AAPLAYRECORD_STATUS_SEEKING;
  1290.                     AcmAppPlayRecordStatus(hwnd, paafd);
  1291.                     break;
  1292.  
  1293.  
  1294.                 case IDCANCEL:
  1295.                     if (gfFileOpen)
  1296.                     {
  1297.                         AcmAppPlayRecordStop(hwnd, paafd);
  1298.                         AcmAppPlayRecordStatus(hwnd, paafd);
  1299.  
  1300.                         AcmAppPlayRecordClose(hwnd, paafd);
  1301.                     }
  1302.  
  1303.                     EndDialog(hwnd, gfDirty);
  1304.                     break;
  1305.             }
  1306.             break;
  1307.     }
  1308.  
  1309.     return (FALSE);
  1310. } // AcmAppPlayRecord()
  1311.