home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_144 / 8.ddi / SOUNDPLY.ZIP / SOUNDPLY.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  14.9 KB  |  514 lines

  1. // ObjectWindows - (C) Copyright 1992 by Borland International
  2.  
  3.  
  4. /* This example demonstrates the use of MCI APIs in Windows 3.1 in an OWL
  5.  *  application:
  6.  *
  7.  * You must have a sound board/Speaker and its device driver installed under
  8.  * Windows 3.1 and be certain that it works -- Use the sound applet in Windows
  9.  * Control Pannel to generate a sound.  You may copy one of the .WAV files from
  10.  * the WINDOWS subdirectory in your system to this example's subdirectory.
  11.  *
  12.  * Run the .EXE.  Choose File:Open and select a .WAV file.  Choose Control:Play
  13.  * to play the waveform.  The Control menu lets you stop/play/pause and resume.
  14.  * The scrollbar allows random access through the waveform while it is playing.
  15.  * This example demonstrates the use of the MCI API and a callback via
  16.  * WM_MCINOTIFY.
  17.  */
  18.  
  19. #include <string.h>
  20. #include <stdio.h>
  21. #include <owl.h>
  22. #include <filedial.h>
  23. #include <button.h>
  24. #include <scrollba.h>
  25. #include <math.h>
  26. #include <mmsystem.h>
  27. #include "soundply.h"
  28.  
  29. #define ID_SCROLL     150            // Scroll bar
  30. #define TIMER_ID     264            // Unique timer ID.
  31.  
  32. // The waveform device opened.
  33. WORD    wDeviceID = 0;
  34. BOOL    flushNotify = FALSE;
  35.  
  36. class TSoundBar : public TScrollBar
  37. {
  38. private:
  39.     int    waveRatio;
  40.     LONG    waveLength;
  41.     char    elementName[255];
  42.  
  43.     void RePosAndPlay (LONG newPos);
  44. public:
  45.     TSoundBar(PTWindowsObject AParent, int AnId, int X, int Y, int W,
  46.              int H, BOOL IsHScrollBar, PTModule AModule = NULL) :
  47.         TScrollBar(AParent, AnId, X, Y, W, H, IsHScrollBar, AModule) {};
  48.  
  49.     void ScrollSetInfo (int wRatio, LONG wLength);
  50.    void ScrollSetName (char *eName);
  51.  
  52.     virtual void SBLineUp(RTMessage Msg) = [NF_FIRST + SB_LINEUP];
  53.     virtual void SBLineDown(RTMessage Msg) = [NF_FIRST + SB_LINEDOWN];
  54.     virtual void SBPageUp(RTMessage Msg) = [NF_FIRST + SB_PAGEUP];
  55.     virtual void SBPageDown(RTMessage Msg) = [NF_FIRST + SB_PAGEDOWN];
  56.     virtual void SBThumbPosition(RTMessage Msg) = [NF_FIRST + SB_THUMBPOSITION];
  57.     virtual void SBTop(RTMessage Msg) = [NF_FIRST + SB_TOP];
  58.     virtual void SBBottom(RTMessage Msg) = [NF_FIRST + SB_BOTTOM];
  59. };
  60.  
  61.  
  62. // Define a class derived from TApplication
  63. class TSoundApp :public TApplication
  64. {
  65. public:
  66.     TSoundApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance,
  67.              LPSTR lpCmdLine, int nCmdShow)
  68.         : TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {};
  69.     virtual void InitMainWindow();
  70. };
  71.  
  72. _CLASSDEF(TSoundWindow)
  73. class TSoundWindow : public TWindow
  74. {
  75. private:
  76.     char        elementName[255];
  77.    int        running;
  78.    int        pause;
  79.    UINT        timeGoing;
  80.     int        waveRatio;
  81.    LONG        waveLength;
  82.    TSoundBar    *tScroll;
  83.     MCI_GENERIC_PARMS    MciGenParm;
  84.     MCI_OPEN_PARMS        MciOpenParm;
  85.     MCI_PLAY_PARMS        MciPlayParm;
  86.    MCI_STATUS_PARMS    MciStatusParm;
  87.    MCI_SET_PARMS        MciSetParm;
  88.  
  89.     void GetDeviceInfo ();
  90.    void StopWave ();
  91.     void StopMCI ();
  92. public:
  93.     TSoundWindow (PTWindowsObject Parent, LPSTR Title);
  94.    ~TSoundWindow ();
  95.  
  96.     void UpdateSoundWindow ();
  97.  
  98.     virtual void GetWindowClass (WNDCLASS &WndClass);
  99.    virtual void SetupWindow();
  100.     virtual LPSTR GetClassName ();
  101.     virtual void MciNotify (RTMessage Msg) = [WM_FIRST + MM_MCINOTIFY];
  102.     virtual void Paint (HDC PaintDC, PAINTSTRUCT _FAR &PaintInfo);
  103.    virtual void FileOpen (RTMessage Msg) = [CM_FIRST + SM_OPEN];
  104.    virtual void FileExit (RTMessage Msg) = [CM_FIRST + SM_EXIT];
  105.    virtual void PlayWave (RTMessage Msg) = [CM_FIRST + SM_PLAY];
  106.    virtual void PauseWave (RTMessage Msg) = [CM_FIRST + SM_PAUSE];
  107.    virtual void HelpAbout (RTMessage Msg) = [CM_FIRST + SM_ABOUT];
  108.    virtual void IdleStuff (RTMessage Msg) = [WM_FIRST + WM_TIMER];
  109. };
  110.  
  111. void TSoundBar::RePosAndPlay (LONG newPos)
  112. {
  113. MCI_PLAY_PARMS MciPlayParm;
  114. MCI_SEEK_PARMS MciSeekParm;
  115. MCI_SET_PARMS MciSetParm;
  116. MCI_OPEN_PARMS MciOpenParm;
  117. MCI_GENERIC_PARMS MciGenParm;
  118.  
  119.    // Only allow SEEK if playing.
  120.    if (!wDeviceID)
  121.         return;
  122.  
  123.     // Close the currently playing wave.
  124.    flushNotify = TRUE;
  125.     MciGenParm.dwCallback = 0L;
  126.     mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  127.     mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  128.  
  129.    // Open the wave again and seek to new position.
  130.     MciOpenParm.dwCallback = 0L;
  131.     MciOpenParm.wDeviceID = wDeviceID;
  132.     MciOpenParm.wReserved0 = 0;
  133.     MciOpenParm.lpstrDeviceType = NULL;
  134.     MciOpenParm.lpstrElementName = elementName;
  135.     MciOpenParm.lpstrAlias = NULL;
  136.  
  137.     if (mciSendCommand (wDeviceID, MCI_OPEN, MCI_WAIT| MCI_OPEN_ELEMENT,
  138.       (DWORD)(LPMCI_OPEN_PARMS)&MciOpenParm)) {
  139.            MessageBox (HWindow, "Open Error", "Sound Play", MB_OK);
  140.            return;
  141.       }
  142.    wDeviceID = MciOpenParm.wDeviceID;
  143.  
  144.    // Our time scale is in SAMPLES.
  145.     MciSetParm.dwTimeFormat = MCI_FORMAT_SAMPLES;
  146.    if (mciSendCommand (wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
  147.       (DWORD)(LPMCI_SET_PARMS)&MciSetParm)) {
  148.        MessageBox (HWindow, "Set Time Error", "Sound Play", MB_OK);
  149.        return;
  150.    }
  151.  
  152.    // Compute new position, remember the scrollbar range has been scaled based on waveRatio.
  153.    MciSeekParm.dwCallback = NULL;
  154.    MciSeekParm.dwTo = ((newPos * waveRatio) > waveLength) ? waveLength : (newPos * waveRatio);
  155.    if (mciSendCommand (wDeviceID, MCI_SEEK, MCI_TO,
  156.       (DWORD)(LPMCI_SEEK_PARMS)&MciSeekParm)) {
  157.        MessageBox (HWindow, "Seek Error", "Sound Play", MB_OK);
  158.        return;
  159.    }
  160.  
  161.     MciPlayParm.dwCallback = (unsigned long)HWindow;
  162.     MciPlayParm.dwFrom = 0;
  163.     MciPlayParm.dwTo = 0;
  164.     if (mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY,
  165.       (DWORD) (LPMCI_PLAY_PARMS)&MciPlayParm)) {
  166.         MessageBox (HWindow, "Play Error", "Sound Play", MB_OK);
  167.         return;
  168.    }
  169. }
  170.  
  171. void TSoundBar::ScrollSetInfo (int wRatio, LONG wLength)
  172. {
  173.     waveRatio = wRatio;
  174.    waveLength = wLength;
  175. }
  176.  
  177. void TSoundBar::ScrollSetName (char *eName)
  178. {
  179.     strcpy (elementName, eName);
  180. }
  181.  
  182. void TSoundBar::SBLineUp(RTMessage msg)
  183. {
  184.     TScrollBar::SBLineUp (msg);
  185.     RePosAndPlay (GetPosition ());
  186. }
  187.  
  188. void TSoundBar::SBLineDown(RTMessage msg)
  189. {
  190.     TScrollBar::SBLineDown (msg);
  191.     RePosAndPlay (GetPosition ());
  192. }
  193.  
  194. void TSoundBar::SBPageUp(RTMessage msg)
  195. {
  196.     TScrollBar::SBPageUp (msg);
  197.     RePosAndPlay (GetPosition ());
  198. }
  199.  
  200. void TSoundBar::SBPageDown(RTMessage msg)
  201. {
  202.     TScrollBar::SBPageDown (msg);
  203.     RePosAndPlay (GetPosition ());
  204. }
  205.  
  206. void TSoundBar::SBThumbPosition(RTMessage msg)
  207. {
  208.     TScrollBar::SBThumbPosition (msg);
  209.     RePosAndPlay (GetPosition ());
  210. }
  211.  
  212. void TSoundBar::SBTop(RTMessage msg)
  213. {
  214.     TScrollBar::SBTop (msg);
  215.     RePosAndPlay (GetPosition ());
  216. }
  217.  
  218. void TSoundBar::SBBottom(RTMessage msg)
  219. {
  220.      TScrollBar::SBBottom (msg);
  221.     RePosAndPlay (GetPosition ());
  222. }
  223.  
  224.  
  225. // Construct the THelloApp's MainWindow data member
  226. void TSoundApp::InitMainWindow()
  227. {
  228.     MainWindow = new TSoundWindow(NULL, "OWL SoundPlay Demo ... using MCI");
  229. }
  230.  
  231.  
  232. int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  233.     LPSTR lpCmdLine, int nCmdShow)
  234. {
  235.     TSoundApp SoundApp ("SoundApp", hInstance, hPrevInstance, lpCmdLine,
  236.                         nCmdShow);
  237.     SoundApp.HAccTable = LoadAccelerators (hInstance, "ACCELERATORS_1");
  238.     SoundApp.Run();
  239.     return SoundApp.Status;
  240. }
  241.  
  242. // Construct the TSoundWindow
  243. TSoundWindow::TSoundWindow (PTWindowsObject Parent, LPSTR Title) :
  244.     TWindow (Parent, Title)
  245. {
  246.    AssignMenu (ID_MENU);
  247.     Attr.X = 50;
  248.     Attr.Y = 100;
  249.     Attr.W = 400;
  250.     Attr.H = 150;
  251.  
  252.    running = 0;
  253.    pause = 0;
  254.    waveLength = waveRatio = 0;
  255.    elementName[0] = '\0';
  256.  
  257.    tScroll = new TSoundBar (this, ID_SCROLL, 50, 67, 300, 0, TRUE);
  258. }
  259.  
  260. void TSoundWindow::SetupWindow()
  261. {
  262.    TWindow::SetupWindow();
  263.    tScroll->SetRange (0, 0);
  264. }
  265.  
  266. TSoundWindow::~TSoundWindow ()
  267. {
  268.     StopMCI ();
  269. }
  270.  
  271. // Paint member function
  272. void TSoundWindow::Paint (HDC PaintDC, PAINTSTRUCT _FAR &)
  273. {
  274.     char buffer[100];
  275.  
  276.    // File name.
  277.    if (lstrlen (elementName))
  278.         TextOut (PaintDC, 5, 5, elementName, lstrlen(elementName));
  279.    else
  280.          TextOut (PaintDC, 5, 5, "<No WAVEFORM file loaded>", 25);
  281.  
  282.    TextOut (PaintDC, 160, 35, "Samples:", 8);
  283.  
  284.    TextOut (PaintDC, 50, 48, "0", 1);        // Beginning value.
  285.  
  286.    // Ending number of samples.
  287.     if (waveLength)
  288.         sprintf (buffer, "%d", waveLength * waveRatio);
  289.    else
  290.       strcpy (buffer, "Unknown");
  291.     TextOut (PaintDC, 315, 48, buffer, lstrlen (buffer));
  292. }
  293.  
  294. // GetClassWindow member
  295. void TSoundWindow::GetWindowClass (WNDCLASS &WndClass)
  296. {
  297.     TWindow::GetWindowClass(WndClass);
  298. }
  299.  
  300. // GetClassName member
  301. LPSTR TSoundWindow::GetClassName ()
  302. {
  303.     return "SoundPlay";
  304. }
  305.  
  306. void TSoundWindow::GetDeviceInfo ()
  307. {
  308. WAVEOUTCAPS    wOutCaps;
  309.  
  310.     if (!waveOutGetDevCaps (wDeviceID, (LPWAVEOUTCAPS)&wOutCaps,
  311.       sizeof (wOutCaps))) {
  312.         MessageBox (HWindow, "GetDevCaps Error", "Sound Play", MB_OK);
  313.         return;
  314.     }
  315. }
  316.  
  317. // Play the wave...
  318. void TSoundWindow::PlayWave (RTMessage)
  319. {
  320.     if (!running) {
  321.         // MCI APIs to open a device and play a .WAV file, using
  322.       // notification to close
  323.         MciOpenParm.dwCallback = 0L;
  324.         MciOpenParm.wDeviceID = 0;
  325.         MciOpenParm.wReserved0 = 0;
  326.         MciOpenParm.lpstrDeviceType = NULL;
  327.         MciOpenParm.lpstrElementName = elementName;
  328.         MciOpenParm.lpstrAlias = NULL;
  329.  
  330.         if (mciSendCommand (0, MCI_OPEN, (DWORD) (MCI_WAIT | MCI_OPEN_ELEMENT),
  331.          (DWORD)(LPMCI_OPEN_PARMS)&MciOpenParm)) {
  332.             MessageBox (HWindow,
  333.           "Open Error - a waveForm output device is necessary to use this demo.",
  334.           "Sound Play", MB_OK);
  335.             return;
  336.         }
  337.        wDeviceID = MciOpenParm.wDeviceID;
  338.  
  339.       // The time format in this demo is in Samples.
  340.       MciSetParm.dwCallback = 0L;
  341.         MciSetParm.dwTimeFormat = MCI_FORMAT_SAMPLES;
  342.       if (mciSendCommand (wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
  343.          (DWORD)(LPMCI_SET_PARMS)&MciSetParm)) {
  344.             MessageBox (HWindow, "SetTime Error", "Sound Play", MB_OK);
  345.             return;
  346.       }
  347.  
  348.         MciPlayParm.dwCallback = (unsigned long)HWindow;
  349.         MciPlayParm.dwFrom = 0;
  350.         MciPlayParm.dwTo = 0;
  351.         mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY,
  352.          (DWORD) (LPMCI_PLAY_PARMS)&MciPlayParm);
  353.  
  354.       // Modify the menu to toggle PLAY to STOP, and enable PAUSE.
  355.         HMENU hMenu = GetMenu (HWindow);
  356.         ModifyMenu (hMenu, SM_PLAY, MF_STRING, SM_PLAY, "&Stop");
  357.         EnableMenuItem (hMenu, SM_PAUSE, MF_ENABLED);
  358.       // Make sure the Play/Stop toggle menu knows we're running.
  359.         running = TRUE;
  360.  
  361.       // Start a timer to show our progress through the waveform file.
  362.       timeGoing = SetTimer (HWindow, TIMER_ID, 500, NULL);
  363.  
  364.       // Give enough information to the scrollbar to monitor the
  365.       // progress and issue a re-MCI_OPEN.
  366.         tScroll->ScrollSetName (elementName);
  367.    } else
  368.        StopWave ();
  369. }
  370.  
  371. void TSoundWindow::PauseWave (RTMessage)
  372. {
  373.     if (!pause) {
  374.       // Pause the playing.
  375.         MciGenParm.dwCallback = 0L;
  376.         mciSendCommand (wDeviceID, MCI_PAUSE, MCI_WAIT,
  377.           (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  378.  
  379.       // Toggle Pause menu to Resume.
  380.         HMENU hMenu = GetMenu (HWindow);
  381.         ModifyMenu (hMenu, SM_PAUSE, MF_STRING, SM_PAUSE, "&Resume\tCtrl+R");
  382.       pause = TRUE;
  383.     } else {
  384.       // Resume the playing.
  385.         MciGenParm.dwCallback = 0L;
  386.         mciSendCommand (wDeviceID, MCI_RESUME, MCI_WAIT,
  387.          (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  388.  
  389.       // Toggle Resume menu to Pause.
  390.         HMENU hMenu = GetMenu (HWindow);
  391.         ModifyMenu (hMenu, SM_PAUSE, MF_STRING, SM_PAUSE, "P&ause\tCtrl+P");
  392.       pause = FALSE;
  393.    }
  394. }
  395.  
  396. void TSoundWindow::StopMCI ()
  397. {
  398.     if (timeGoing)            // Timer running, then kill it now.
  399.         timeGoing = !KillTimer (HWindow, TIMER_ID);
  400.  
  401.    // Stop playing the waveform file and close the waveform device.
  402.     MciGenParm.dwCallback = 0L;
  403.     mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT,
  404.       (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  405.     mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT,
  406.       (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
  407.  
  408.     running = FALSE;
  409.    wDeviceID = 0;
  410. }
  411.  
  412. void TSoundWindow::StopWave ()
  413. {
  414.    if (wDeviceID) {
  415.         StopMCI ();
  416.  
  417.       // Reset the menus to Play menu and gray the Pause menu.
  418.        HMENU hMenu = GetMenu (HWindow);
  419.        ModifyMenu (hMenu, SM_PLAY, MF_STRING, SM_PLAY, "&Play\tCtrl+P");
  420.        ModifyMenu (hMenu, SM_PAUSE, MF_STRING | MF_GRAYED, SM_PAUSE, "P&ause\tCtrl+A");
  421.    }
  422. }
  423.  
  424. void TSoundWindow::FileOpen (RTMessage)
  425. {
  426. char    FileName[MAXPATH];
  427.  
  428.     if ( GetApplication()->ExecDialog(new TFileDialog(this, SD_FILEOPEN, strcpy(FileName, "*.WAV"))) == IDOK )
  429.             if (CanClose()) {
  430.             // Remember the waveform file to open.
  431.                 strcpy (elementName, FileName);
  432.  
  433.             // Turn the Play menu on.
  434.             HMENU hMenu = GetMenu (HWindow);
  435.             EnableMenuItem (hMenu, SM_PLAY, MF_ENABLED);
  436.  
  437.             waveLength = 0;
  438.             waveRatio = 0;
  439.                 tScroll->SetPosition (0);
  440.             UpdateSoundWindow ();
  441.          }
  442. }
  443.  
  444. void TSoundWindow::FileExit (RTMessage)
  445. {
  446.     CloseWindow ();
  447. }
  448.  
  449. // Response function MM_MCINOTIFY message when MCI_PLAY is complete.
  450. void TSoundWindow::MciNotify (RTMessage)
  451. {
  452. int    loVal, hiVal;
  453.  
  454.    if (!flushNotify) {             // Internal STOP/CLOSE, from thumb re-pos?
  455.         StopWave ();
  456.  
  457.         // Make sure the thumb is at the end. There could be some WM_TIMER messages on the queue when
  458.         // we kill it, thereby flushing WM_TIMER's from the message queue.
  459.         tScroll->GetRange (loVal, hiVal);
  460.         tScroll->SetPosition (hiVal);
  461.     }
  462.    flushNotify = FALSE;             // Yes, so ignore the close.
  463. }
  464.  
  465.  
  466. void TSoundWindow::UpdateSoundWindow ()
  467. {
  468. RECT    r;
  469.  
  470.     // First time it's different update the scroll bar numbers.
  471.     GetClientRect (HWindow, &r);
  472.     InvalidateRect (HWindow, &r, TRUE);
  473. }
  474.  
  475.  
  476. void TSoundWindow::HelpAbout (RTMessage)
  477. {
  478.     MessageBox (HWindow, "SoundPly loads and plays waveform sound \
  479. files (*.WAV).  The features of this demo are Play/Stop, Pause/Resume, \
  480. and random seeks through the file via the scollbar (while the sound is \
  481. playing).  NOTE: SoundPly will only play sounds if the machine contains \
  482. a waveForm Multimedia device, e.g. SoundBlaster, etc.).",
  483.    "About Sound Play", MB_OK);
  484. }
  485.  
  486. void TSoundWindow::IdleStuff (RTMessage)
  487. {
  488.     if (!flushNotify) {            // Internal STOP/CLOSE, from thumb re-pos?
  489.         MciStatusParm.dwCallback = 0L;    // No, normal close.
  490.         MciStatusParm.dwItem = MCI_STATUS_LENGTH;
  491.         mciSendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPMCI_STATUS_PARMS)&MciStatusParm);
  492.         if (waveLength != MciStatusParm.dwReturn) {
  493.                         // First time it's different update the scroll bar numbers.
  494.                         UpdateSoundWindow ();
  495.                     waveLength = MciStatusParm.dwReturn;
  496.         }
  497.  
  498.             // Compute the length and ratio and update tScroll info.
  499.         waveRatio = (int)ceill((waveLength / 32000) + .5);
  500.         tScroll->ScrollSetInfo (waveRatio, waveLength);
  501.         tScroll->SetRange (0, (int)(waveLength / waveRatio));
  502.  
  503.             // Update the current position.
  504.          MciStatusParm.dwCallback = 0L;
  505.          MciStatusParm.dwItem = MCI_STATUS_POSITION;
  506.          mciSendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPMCI_STATUS_PARMS)&MciStatusParm);
  507.  
  508.          tScroll->SetPosition ((int)(MciStatusParm.dwReturn / waveRatio));
  509.    }
  510.  
  511.    flushNotify = FALSE;             // Yes, ignore this close.
  512. }
  513.  
  514.