Delphi: playing Chimes.wav as an external file or embedded WAVE resource in Delphi XE5.
Posted by jpluimers on 2018/01/10
As a by-effect, this article seems to one of the few that shows where Delphi uses the
.dres
file extension introduced around Delphi XE.
Recently I had to play some notification sounds in a Windows Delphi application where the application deployment should be as easy as possible: preferable copying the EXE around.
Playing a sound file seems easy, especially if it is a [WayBack] WAV file: just use the [WayBack] PlaySound or the (older) [WayBack] sndPlaySound API functions.
But if you start searching on the internet, you see lots of curious implementations for playing WAV resources through sndPlaySound.
The actual implementation is really really easy though, just make sure you follow the steps right and nothing can go wrong.
[WayBack] The full source code is on my BeSharp.net repository, here is how to to it step by step:
The steps depend on the
MMSystem
unit, so most of the code translates back to [WayBack] Turbo Pascal for Windows (yes, the 16-bit Pascal days when theMMSystem
unit was introduced) with the exception of theSND_SENTRY
flag.The thing that more recent Delphi versions made a lot easier is embedding
WAV
files asWAVE
resources, more on that further on.
All examples use the combination of the flags SND_NODEFAULT
, SND_ASYNC
or SND_SENTRY
:
SND_NODEFAULT
makes sure no other sound gets substituted if the file or resource cannot be found.SND_ASYNC
plays the sound asynchronously in a separate thread so your main thread continues to execute while the sound plays.SND_SENTRY
is for [WayBack] Windows Vista and up to notify hearing impaired in a visual way that a sound is being played through aSoundSentry
event.
Stop playing sound
Playing sounds starts with stopping anything that is playing from your current app with this line of code:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PlaySound(nil, 0, SND_ASYNC); |
It uses the nil as a sound parameter in combination with the SND_ASYNC flag to stop playing any sound that started using the PlaySound or sndPlaySound functions in your application.
Playing a WAV
file
This is also a one-liner.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PlaySound('C:\Windows\Media\chimes.wav', 0, SND_FILENAME or SND_NODEFAULT or SND_ASYNC or SND_SENTRY); |
The initial demo project is a bit larger, as it involves a VCL Form and a project just for the single purpose on showing how the project will change when embedding a WAVE resource.
Embedding a WAV
file as a WAVE
resource

“MARKDOWN_HASH4d6405500fb43f9f98154b18224bc165MARKDOWN_HASH
” in the “MARKDOWN_HASH9e727fdd3aec8274f46685441900280dMARKDOWN_HASH
” menu
In the past this was overly complicated: people were manually assembling RES files, or wrote [WayBack] RC scripts to create RES files and included those in Delphi.
No need for that any more: somewhere around Delphi XE this got much easier:
- Open the
Project
menu, then chooseResources and Images...
just like shown on the right: -
Press the
Add
button:
- Choose a
.WAV
file (in this caseC:\Windows\Media\chimes.wav
)
- Rename the resource to
chimes_wav
(to make sure there is no.
in it):
- Ensure the
Resource type
is [WayBack]WAVE
(PlaySound requires it, so do not use RCDATA or RC_DATA [WayBack]):
Performing the above steps result in a few very interesting changes in your Delphi project.
A. The cool thing is that Delphi now has embedded the resource as an external link the the .dproj
file, as seen by this diff:
B. The .dpr
file also got changed loading the *.dres
file in-between the program and uses like:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
program PlayChimesWavAsEmbeddedResourceVclProject; | |
{$R *.dres} | |
uses |
Now you only need to add one more line of code to play this embedded WAVE
resource…
Playing a WAVE resource
Two changes you need to do here:
- Use the resource name, not the file name.
SND_RESOURCE
flag.
Note there is no need any more for uppercase resource names, but there cannot be any periods in them as the [WayBack] valid characters in resource names are limited to A-Z, a-z, 0-9, and underscores ( _ ) and resource names must be unique in the scope of the application (not only the resource file).
So the line becomes this:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
PlaySound('chimes_wav', HInstance, SND_RESOURCE or SND_NODEFAULT or SND_ASYNC or SND_SENTRY); |
leaving the diff like this:
So there is [WayBack] no need to use FindResource
, LoadResource
, LockResource
, nor [WayBack] TResourceStream
. You still can, but that makes it overly complicated.
With the PlaySound solution above, you might need to cast the string of the filename or resource name to PChar
if you pass the string as variable, but that is about as complicated as it gets.
Playing from memory
I haven’t included an example for playing sounds from memory. The reason is that using [WayBack] SND_MEMORY
with SND_ASYNC
requires you to make sure [WayBack] the memory buffer lasts longer than the sound will play. And since the sound plays asynchronously in a separate thread, you have to make sure the memory outlives the thread. Which can be hard.
As of Windows 7, Microsoft fixes this by buffering up to a maximum of 2 megabytes of WAV data for you, but still you need to be careful.
Playing cross plaform
When you want to play sounds in a cross platform way, you need to look into the FireMonkey [Archive.is] FMX TMediaPlayer
. That is beyond the scope of this blog post, but a [WayBack] Delphi XE4 example is here.
–jeroen
keywords:
PlaySound(nil, 0, SND_ASYNC);
Leave a Reply