Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

The Ultimate Toolbox Sound Manager

0.00/5 (No votes)
25 Aug 2007 1  
Classes from the Ultimate toolbox that allow configuring customized dialog item sound effects

Visit the Ultimate Toolbox main page for an overview and configuration guide to the Ultimate Toolbox library.

Source code and project files for this sample can be found in the samples\utility\SoundManager directory of the sample projects download.

Overview

COXSoundEffectManager

Nowadays, more and more computers are equipped with a sound card and sound effects can add another professional feature that distinguish your software. Of course, sound effects are a must for multimedia applications but sometimes it's nice to add some sounds in a regular application too. Wouldn't it be nice to hear some sound when you click over button or play some sound when the mouse moves over some object. Using our new classes it takes only one line of code to associate a sound effect with any object so this effect will be played when specified event is fired.

Note that sounds are usually played in result of some user action (e.g. the mouse left button was clicked or a specific keyboard button was pressed) or in result of some event (e.g. a timer event). Any event which eventually forces an application to play sound we call a sound event. To uniquely identify any such event we define a sound event ID. This approach works well with natural events such as mouse or keyboard events.

In the case when the sound is played due to an application specific event we define it as an application specific message.

Any sound played with in response to a windows message we call a sound message. Now the idea behind the COXSoundEffectManager class should be clear. Why don't we create the class that will manage sound effects and sound events? It should be only one function to register a sound to be played when a particular event is fired! And as long as sound events are defined as window messages we can come up with the class that will work with any object (static, edit, combobox, button, listbox, tree, list controls etc.).

The COXHookWnd class is the parent class of COXSoundEffectManager. Basically, we hook a window and examine all messages. If the message currently being handling is registered as a sound event message we start to play associated sound using our COXSound class.

Usage

Since COXSoundEffectManager is derived from COXHookWnd any target window must be attached to COXSoundEffectManager object using the Attach method.

After the window is successfully attached you can register whatever sound events are to be played when the corresponding event is fired using RegisterPlayEvent.

You can use an existing sound file or resource from your application as source of sound and you can set additional options that define the way the sound is played. The sound can be played only once, infinitely or for a fixed number of times. You can also specify whether the sound should be started even though another may be playing.

Some sounds can be pretty lengthy (especially if you used the loop infinitely option). Although any playing sound will be stopped when the hooked window is destroyed or detached using the Detach function, sometimes it's good idea to define some events that would cause any playing sound to be stopped after being fired. We call such events sound stop events (the sound events that were described before we call sound play events). To register such an event we use the RegisterStopEvent method.

Of course the same event cannot be registered to play different sounds and cannot be registered as play and stop event simultaneously.

Any stop or play sound events can be unregistered using UnregisterPlayEvent or UnregisterStopEvent.

To unregister all events simultaneously use UnregisterAllEffects, UnregisterAllPlayEvents, or UnregisterAllStopEvents.

At any time you can test whether a particular event is registered as stop or play sound event using IsRegisteredPlayEvent or IsRegisteredStopEvent.

While programming using COXSoundEffectManager class to its fullest extent you will find GetSoundEffect very useful.

Persistence

You have the option to save, in the registry, all registered play and stop sound events and sound effects. Use SaveState to save to the registry and LoadState to retrieve the previously saved state.

If you don't want to save the state of the Sound Effect Manager settings into the registry then you can add the OXSE_NO_SAVESTATE define to your project and remove the source code for COXRegistryValFile.

COXSoundEffectOrganizer

The COXSoundEffectManager has two weaknesses.

First of all, it is designed to handle only with one target window at a time. That means if you want to assign sound effects to five buttons then you have to create five COXSoundEffectManager objects which adds a lot of weight to your source code. To resolve this problem we created the COXSoundEffectOrganizer class which can be used to register sound effects for multiple windows. Internally this class creates a COXSoundEffectManager object for every registered window, but hides this fact from a programmer while providing the same functionality as COXSoundEffectManager does. Plus COXSoundEffectOrganizer is aware off all COXSoundEffectManager objects it manages and can stop or start playing sounds in any of them (that is why the COXSoundEffectManager constructor is designed to take pointer to a COXSoundEffectOrganizer object as parameter which must be set to NULL if the COXSoundEffectManager object is used as stand-alone).

The samples\utility\SoundManager sample dialog uses a member COXSoundEffectOrganizer object (include OXSoundEffectManager.h) to add mouse enter and click sounds to static controls on the dialog. (These static controls are subclassed COXStaticText objects with overrides that enhance the visual effects of the enter and click events).

The dialog implements a member function SetupStaticControl that is called from OnInitDialog to initialize color and sound effect events:

void CSoundManagerDlg::SetupStaticControl(CMyStatic* m_pctl, COLORREF clrText,
                                          COLORREF clrBack, int nFontHeight, 
                                          int nFontWeight,CString sFontName,
                                          BOOL bEmboss, int nHorzAlignment,
                                          int nVertAlignment, 
                                          CString sEnterSound,
                                          CString sClickSound) 
{
    m_pctl->SetTextColor(clrText);
    m_pctl->SetBkColor(clrBack);
    LOGFONT lf;
    if(m_pctl->GetLogFont(&lf))
    {
        lf.lfHeight=nFontHeight;
        lf.lfWeight=nFontWeight;
        m_pctl->SetLogFont(&lf);
    }
    m_pctl->SetFontName(sFontName);

    m_pctl->SetEmboss(bEmboss);
    m_pctl->SetHorzAlignment(nHorzAlignment);
    m_pctl->SetVertAlignment(nVertAlignment);
    m_pctl->SetCharSet(ANSI_CHARSET,TRUE);

    VERIFY(m_SoundEffectOrganizer.
        RegisterPlayEvent(m_pctl,WM_LBUTTONDOWN,sEnterSound));
    VERIFY(m_SoundEffectOrganizer.RegisterPlayEvent(m_pctl,HWM_MOUSEENTER,
        sClickSound,FALSE,-1,FALSE));
}

And sets the properties of the COXStaticHyperLink 'about' control in the OnInitDialog method. (The heartbeat is quite scary):

    // set action as userdefined 


    // don't forget to set callback message and handle to recipient window


    if(GetFont()->GetObject(sizeof(lf), &lf))
    {
        lf.lfHeight=-12;
        lf.lfUnderline=FALSE;
        lf.lfWeight=FW_BOLD;
        UTBStr::tcsncpy(lf.lfFaceName, LF_FACESIZE, 
            _T("Arial"),LF_FACESIZE);
        m_ctlAbout.SetTextLogFont(&lf);
    }
    m_ctlAbout.SetUnvisitedColor(RGB(0,128,128));
    m_ctlAbout.SetAction(ID_HLACTION_USERDEFINED,NULL,NULL,NULL,
        SW_SHOWNORMAL,g_nAboutMsgID,GetSafeHwnd());
    m_ctlAbout.SetShowToolTip(TRUE);
    m_ctlAbout.SetToolTipText(_T(
        "Information about COXSoundEffectOrganizer"));
    m_ctlAbout.SetFitToText(FALSE);
    VERIFY(m_SoundEffectOrganizer.RegisterPlayEvent(
        &m_ctlAbout,HWM_MOUSEENTER,
        _T(".\\Sound\\HeartBeat2.wav"),TRUE,-1,TRUE));
    VERIFY(m_SoundEffectOrganizer.RegisterPlayEvent(
        &m_ctlAbout,WM_LBUTTONDOWN,
        _T(".\\Sound\\Camera.wav")));
    VERIFY(m_SoundEffectOrganizer.RegisterStopEvent(&m_ctlAbout,
        HWM_MOUSELEAVE));

It is highly recommended to use COXSoundEffectOrganizer instead of COXSoundEffectManager even in situations when you provide sound effects only for one window.

COXSoundCustomizeDlg

Another problem has to do with customizing of sound effects. Although we provide basic functions to save into and load from registry state of any COXSoundEffectManager object, there is still the issue of providing an easy way for users to customize sound effects. Enter the COXSoundCustomizeDlg class, which layers a pointer to COXSoundEffectOrganizer object and provides the user an interface to add, delete, and edit any sound events and effects for all windows registered with given COXSoundEffectOrganizer object (another reason to use always COXSoundEffectOrganizer instead of COXSoundEffectManager).

History

Initial CodeProject release August 2007.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here