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):
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
).
Initial CodeProject release August 2007.