MFC TIMERS & PROGRESS BARS; WINDOWS MULTIMEDIA

THE WINDOWS TIMER--

An input device that notifies an app when a time interval has elapsed 
     Application starts it & tells Windows the interval with SetTimer()
     Windows sends WM_TIMER message each time interval elapses
     Application stops and removes timer with KillTimer()

Could be used to keep time--but not accurate

CTime class to the rescue!!
     GetCurTime() member function returns hour, minute, and seconds
     Member functions can retrieve these values:
         GetHour(), GetMinute(), GetSecond()

Clock Application <Show program in action>



Use AppWizard to create a Dialog-Based MFC Application template

Add the following controls to the dialog box:
     "Time:" static control
     "Current Time" static control (IDC_STATICTIME)
          (Will show the current time)

Remove the "Cancel" Button
Change the "OK" button to "Exit"

Add the timer ID:
     In Resource View, right-click over "Clock" Resource Folder
     Select "Resource Symbols"
     Hit "New"
     Enter ID_CLK_TIMER
          Will assign an ID to the timer

Starting the Clock Timer with a one-second interval
     In CClockDlg, Edit the OnInitDialog() function by adding:
        // TODO: Add extra initialization here
        SetTimer(ID_CLK_TIMER, 1000, NULL);    

Use ClassWizard to add m_sTime variable to IDC_STATICTIME control
     Type: CString

Use ClassWizard to set up a message handler for WM_TIMER:
     Edit the resulting OnTimer() function:

        // TODO: Add your message handler code here and/or call default
        CTime t=CTime::GetCurrentTime();
        m_sTime.Format("%d:%d:%d", t.GetHour(), 
                         t.GetMinute(), t.GetSecond());
        
        UpdateData(FALSE);  //Send to Static Current Time control           


Progress Bar Controls

Used to indicate progress of an operation
Lets user know what portion of an operation is not yet completed

Encapsulated in CProgressCtrl Class
     Some Member Functions (kind of like Scroll bar functions):
          SetRange() & GetRange() -- range of the progress bar
          SetPos() & GetPos() -- current position
          OffsetPos() -- to increment current progress bar position
          SetStep() -- to set step amount for progress bar
          StepIt() -- to increment position by step amount

TimerProgrss Application <Show  program in action>



Set up an MFC Dialog-based Application template

Add the timer ID:
     In Resource View, right-click over "TimerProgrss" Resource Folder
     Select "Resource Symbols"
     Hit "New"
     Enter ID_CNT_TIMER
          Will assign an ID to the timer

Add following controls:
     "Interval:" static control
     IDC_INTERVAL Edit box
     "Max Count:" static control
     IDC_MAXCNT Edit box
     "Count:" static control
     Static control to hold current count (IDC_STATICCNT, "0")
     IDC_PROGCNT Progress Bar
     
Remove the "Cancel" Button
Change the "OK" button to "Exit"

Use ClassWizard to add the following variables for the controls:

Control ID      Variable Name     Variable Type
------------------------------------------------
IDC_PROGCNT     m_Progress        CProgressCtrl
IDC_START       m_Start           CButton
IDC_STATICCNT   m_sCount          CString
IDC_INTERVAL    m_iInterval       int
IDC_MAXCNT      m_iMax            int

Add m_iCount member variable (int private) to the TimerProgrssDlg class
     (Right click on the clas)

Use ClassWizard to add the following Message Map handler functions:

CTimerProgrssDlcg -- WM_TIMER:  OnTimer()
IDC_START -- BN_CLICKED:  OnStart()
IDC_INTERVAL -- EN_CHANGE:  OnChangeInterval()
IDC_MAXCNT -- EN_CHANGE:  OnChangeMaxcnt() 

Edit the OnInitDialog() function (initialization of controls):
   // TODO: Add extra initialization here
   m_iInterval=100;
   m_iMax=1000;
   UpdateData(FALSE); //Pass variable data to controls

Edit the OnStart() function (initialize progress bar & start timer):
// TODO: Add your control notification handler code here
   UpdateData(TRUE);   //Get data from controls
   m_iCount=0;
   m_sCount.Format("%d", m_iCount);
   m_Progress.SetRange(0,m_iMax);   //Set progress control
   m_Progress.SetPos(0);
   UpdateData(FALSE);  //Pass new data back to controls
   m_Start.EnableWindow(FALSE); //disable Start button
   SetTimer(ID_CNT_TIMER,m_iInterval,NULL); //Start timer    

Edit the OnTimer() function (timeout, so count and update progress bar):
   // TODO: Add your message handler code here and/or call default
   m_iCount+=m_iInterval;       //Increment count
   m_sCount.Format("%d", m_iCount);
   m_Progress.SetPos(m_iCount); //Set new prog bar position
   UpdateData(FALSE);           //Pass data back to control
   if(m_iCount>=m_iMax)         //If done, kill timer
   {
        KillTimer(ID_CNTTIMER);
        m_Start.EnableWindow(TRUE); // enable start button
   }

Edit the OnChangeInterval() function (Get new interval from Interval control):
   // TODO: Add your control notification handler code here
   UpdateData(TRUE); // Get interval value from edit control

Edit the OnChangeMaxcnt() function (Get new Max from Maxcount control):
   // TODO: Add your control notification handler code here
   UpdateData(TRUE); // Get maxcount value from edit control

Build and Run the application. 
(You may have to make the some of the controls bigger)


WINDOWS MULTIMEDIA

Some multimedia devices:
   Waveform audio device (sound card)
      converts microphone & other analog audio to digitized samples
      can be stored as .WAV files
      can be played back
      Usually has a MIDI device
          plays music from short binary messages
          can be attached to a MIDI input device (music keyboard)
   CD Audio through the CD-ROM drive
   Video for Windows device (AVI video device)
      plays movie/animation files (.AVI)
   Video capture boards (different compression schemes)
   Laserdisc players & video cassette recorders
   Others
     
Extensive Win32 API support for multimedia devices
   Low-level support
   High-level support
   MSDN online documentaton:
      Platform SDK/Graphics & Multimedia Services/Multimedia Reference

MCI (Media Control Interface)
   High level multimedia control functions
   Has commands common to all MM hardware
      Possible since most use record/play metaphor
         Open a device for input or output
         If input, record
         If output, play
         When done, close

   Two forms of MCI
      Send command messages (like Windows messages) to MCI
         (need to include bit-encoded flags and C data structures)
      Send text strings to MCI
         Good for use from scripting languages with string functionality
         Simple to use
         MCI converts them to command messages

mciSendString() function:

error = mciSendString(szCmd, szRetStr, cSzRetStr, hCallback)      

   szCmd--the mci command string (specifies command & device)
   szRetStr--return string buffer (NULL if none used)
   szSzRetStr--size of return string buffer (0 if none used)
   szCallback--Handle to Callback function (NULL if none used)

   Returns 0 if command is successful, error code if not
      Usually used as parameter to mciGetErrorString()

Many command strings possible
See MSDN online help:
/ Platform SDK / Graphics & Multimedia Services / Multimedia Reference
/ Multiemedia Command Strings
   
Some Common MCI Command Strings:

open -- initializes a device
   "open lpszDevice lpszOpenflags lpszFlags"

   Some device types:
      cdaudio -- Audio CD played on system's CD-ROM
      waveaudio -- .WAV audio files
      AVIVideo -- .AVI video files

   Some Examples:
      "open cdaudio"
      "open new type waveaudio alias mysound"  (for recording)
      "open waveaudio!myclip.wav alias clip"

play -- plays from an open device
   "play cdaudio"

stop -- stops playing from an open device
   "stop clip"

close -- closes an open device
   "close mysound"
   
PlayCD Application <show program in action>




Create an MFC AppWizard (.exe) Dialog-based application template

All Multimedia applications must #include the "mmsystem.h" header file
   So add:
       #include "mmsystem.h" at top of PlayCDDlg.h file

Must also link in the WINMM.LIB library--
    Project / Settings / Link Tab / Category: Input / Object-Library Modules
       Type in: WINMM.LIB

Add "Play CD" and "Stop CD" buttons (IDC_BPLAY and IDC_BSTOP)

Use ClassWizard to add Message Map BN_CLICKED handler functions for the two 
new buttons --> OnBplay() & OnBstop()

Add code to OnBplay():
        mciSendString("open cdaudio",NULL,0,NULL);
        mciSendString("play cdaudio",NULL,0,NULL);

Add code to OnBstop():
        mciSendString("stop cdaudio",NULL,0,NULL);
        mciSendString("close cdaudio",NULL,0,NULL);

Build and run with an audio CD in the CD-ROM drive
   You may have to shut down autostart app launched when audio CD is inserted
   It may do stuff to "mute" & "volume" audio controls
      You may have to adjust them


Recording and Playing Digital Sound (.WAV files)
RecPlay Application <show program in action> 



Want to:
   Begin and Stop recording
   Begin and Stop playback
   Save and read a .WAV file

Use mciSendString() to issue command strings

Keep track of what's happening with Booleans bRec and bPlay

Use 5 buttons: ("Begin Rec", "End Rec", "Begin Play", "End Play", "Exit")
   Enable or Disable according to what's happening==>
      Need Button control variables (to access EnableWindow() function)

Requirements:

When app begins execution:
   Set bRec and bPlay to FALSE
   Disable "End Record", "End Play" buttons

"Begin Rec" button pressed==>
   open new waveaudio device & record
   set bRec to TRUE
   disable: "Begin Rec", "Begin Play", "End Play" buttons
   enable: "End Rec" button

"End Rec" button pressed==>
   stop device, save as  .WAV file, close device
   set bRec to FALSE
   disable: "End Rec", "End Play" buttons
   enable: "Begin Rec", "Begin Play" buttons

"Begin Play" button pressed==>
   open  .WAV file & play
   set bPlay to TRUE
   disable: "Begin Rec", "Enc Rec",  Begin Play" buttons
   enable: "End Play" button

"End Play" button pressed==>
   stop & close device
   set bPlay to FALSE
   disable: "End Rec", "End Play" buttons
   enable: "Begin Rec", "Begin Play" buttons
   
"Exit" button pressed==>
   if bPlay is TRUE: execute "End Play" button command function
   if bRec is TRUE: stop & close device (don't save incomplete recording)   
   Exit

RecPlay Application Details:

Create an MFC AppWizard (.exe) Dialog-based application template

Add:  #include "mmsystem.h" at top of RecPlayDlg.h file

Link in the WINMM.LIB library--
    Project / Settings / Link Tab / Category: Input / Object-Library Modules
       Type in: WINMM.LIB

Create Buttons:
   "Begin Rec" (IDC_REC_BEG), "End Rec" (IDC_REC_END)
   "Begin Play" (IDC_PLAY_BEG), "End Play" (IDC_PLAY_END)

Add private BOOL variables: bPlay, bRec (Right click class)

Use ClassWizard to attach Command member variables to the buttons:
   m_cRecBeg, m_cRecEnd, m_ cPlayBeg, m_cPlayEnd (CButton derived)

USe ClassWizard to add Message Map BN_CLICKED handler functions to each button -->
   OnRecBeg(), OnRecEnd(), OnPlayBeg(), OnPlayEnd(), OnOK()

Edit OnInitDialog():
        // TODO: Add extra initialization here
        bPlay=bRec=FALSE;
        m_cRecEnd.EnableWindow(FALSE);
        m_cPlayEnd.EnableWindow(FALSE);

Edit OnRecBeg():
        // TODO: Add your control notification handler code here
        mciSendString("open new type waveaudio alias myvoice",NULL,0,NULL);
        mciSendString("record myvoice",NULL,0,NULL);
        bRec=TRUE;
        m_cRecBeg.EnableWindow(FALSE);
        m_cRecEnd.EnableWindow(TRUE);
        m_cPlayBeg.EnableWindow(FALSE);
        m_cPlayEnd.EnableWindow(FALSE);

Edit OnRecEnd():
        // TODO: Add your control notification handler code here
        mciSendString("stop myvoice",NULL,0,NULL);
        mciSendString("save myvoice test.wav",NULL,0,NULL);
        mciSendString("close mysound",NULL,0,NULL);
        bRec=FALSE;
        m_cRecBeg.EnableWindow(TRUE);
        m_cRecEnd.EnableWindow(FALSE);
        m_cPlayBeg.EnableWindow(TRUE);
        m_cPlayEnd.EnableWindow(FALSE);

Edit OnPlayBeg():
        // TODO: Add your control notification handler code here
        mciSendString("open test.wav alias myvoice",NULL,0,NULL);
        mciSendString("play myvoice",NULL,0,NULL);
        bPlay=TRUE;
        m_cRecBeg.EnableWindow(FALSE);
        m_cRecEnd.EnableWindow(FALSE);
        m_cPlayBeg.EnableWindow(FALSE);
        m_cPlayEnd.EnableWindow(TRUE);

Edit OnPlayEnd():
        // TODO: Add your control notification handler code here
        mciSendString("stop myvoice",NULL,0,NULL);
        mciSendString("close myvoice",NULL,0,NULL);
        bPlay=FALSE;
        m_cRecBeg.EnableWindow(TRUE);
        m_cRecEnd.EnableWindow(FALSE);
        m_cPlayBeg.EnableWindow(TRUE);
        m_cPlayEnd.EnableWindow(FALSE);

Edit OnOK():
        // TODO: Add extra validation here
        if (bPlay)
                OnPlayEnd();
        if(bRecording)
        {
                mciSendString("stop myvoice",NULL,0,NULL);
                mciSendString("close myvoice",NULL,0,NULL);
        }

Build and run the application
You may need to attach an external microphone and
fool around with audio control and microphone settings
   Best to run "Sound Recorder" app first to make sure things are working:
      Start / Programs / Accessories / Entertainment / Sound Recorder