Use wave file from project
Asked Answered
V

4

5

I currently can only playback my background sound from having my wave file next to my compiled exe. But I actually want to have a single static executable with the wave file inside. Is this possible in Delphi XE2?

This is my code:

SndPlaySound('.\Raw.wav', SND_ASYNC or SND_LOOP);
#This will play the Raw.wav that is next to my program.
Vermillion answered 14/5, 2012 at 0:30 Comment(0)
M
6

If you use PlaySound() instead of sndPlaySound(), you can utilize the SND_RESOURCE flag to play the wave sound directly from its resource without having to load it into memory first.

Meaningful answered 14/5, 2012 at 3:34 Comment(1)
Wow, thanks for the shortest and cleanest method! accepted ;)Vermillion
F
11

You can add the SND_MEMORY flag, and pass a TResourceStream.Memory pointer as the first parameter.

First, use XE2's Project->Resources and Images menu item to add a new resource. Give it the path and filename of your .wav file, a resource type of RC_DATA (it's not in the drop down list, but you can manually type it in), and a resource name you can use at runtime to refer to it. (In my example, I'm using C:\Microsoft Office\Office12\MEDIA\APPLAUSE.WAV, and giving it a resource name of APPLAUSE.)

procedure TForm2.Button1Click(Sender: TObject);
var
  Res: TResourceStream;
begin
  Res := TResourceStream.Create(HInstance, 'APPLAUSE', 'RC_DATA');
  try
    Res.Position := 0;
    SndPlaySound(Res.Memory, SND_MEMORY or SND_ASYNC or SND_LOOP);
  finally
    Res.Free;
  end;
end;
Farnesol answered 14/5, 2012 at 0:54 Comment(7)
As soon as I start my program, it displays an error message, telling me that the resource "Raw" is missing. I did everything you said.Vermillion
Did you make the change to RC_DATA that I described? It won't work with the resource editor's RCDATA; you have to manually change it to RC_DATA (note the underscore), and then do a Project->Build. The code I posted works; I ran it on my machine. (That's how I found that you had to change RCDATA to RC_DATA for it to work properly.) Also, makes sure you use RAW instead of Raw; resource names need to be in UPPERCASE.Farnesol
Now it works, sorry for the hassle. ^^' I had to use UPPERCASE and the underscore that I didn't notice at first. You are my hero! :DVermillion
Or you can use the resource type RCDATA defined by the DELPHI combobox... and then, Res := TResourceStream.Create(HInstance, 'APPLAUSE', RT_RCDATA); (instead of creating custom constants...)Jeffcott
@KenWhite: I ALSO tested... and it works with my Delphi XE2 and 7x64Jeffcott
@KenWhite: did you notice the RT_ ? ;o) ` RT_RCDATA = System.Types.RT_RCDATA; //MakeIntResource(10);`Jeffcott
If you use SND_RECOURCE, and use resource type WAVE in Resources and Images, there is no need for the TResourceStream any more: PlaySound just picks up the resource fine. I will put that in an answer with example source code when I have finished my blog article. +1 though for RC_DATA and RC_RCDATA.Galle
M
6

If you use PlaySound() instead of sndPlaySound(), you can utilize the SND_RESOURCE flag to play the wave sound directly from its resource without having to load it into memory first.

Meaningful answered 14/5, 2012 at 3:34 Comment(1)
Wow, thanks for the shortest and cleanest method! accepted ;)Vermillion
V
4

type "WAVE" as Resource type when importing the wav file in the Resource Editor (Delphi 10, Project, Resources and Images) and simply use

   PlaySound(resourceIndentifierName, 0, SND_RESOURCE or SND_ASYNC);

P.S. uppercase no longer required

Vervet answered 24/12, 2017 at 11:31 Comment(2)
This is the best answerBundelkhand
Yes this is the most straightforward (updated) answer !Hypocotyl
J
2

Just tested and it works on mine:

var
  hFind, hRes: THandle;
  Song       : PChar;
begin
  hFind := FindResource(HInstance, 'BATTERY', 'WAV');
  if (hFind <> 0) then
  begin
    hRes := LoadResource(HInstance, hFind);
    if (hRes <> 0) then
    begin
      Song := LockResource(hRes);
      if Assigned(Song) then
      begin
        SndPlaySound(Song, snd_ASync or snd_Memory);
      end;
      UnlockResource(hRes);
    end;
    FreeResource(hFind);
  end;

enter image description here

Jeffcott answered 14/5, 2012 at 1:23 Comment(5)
You can still add the loop (SND_LOOP).. but I'm not sure this is really what you want...Jeffcott
Delphi has a built-in class for accessing resources (TResourceStream), as I posted. Why jump through hoops of calling the API functions (including having to lock and unlock them) when Delphi does all the work for you?Farnesol
Thanks for your help guys, but my hero Ken White already did the job super well.Vermillion
@KenWhite: I agree... your solution is nicer and deserves the accepted ;o) (but mine works also)Jeffcott
I didn't say it wouldn't work. You can also create a Windows application without using Delph's VCL and the Forms unit by using straight API calls, but why would you want to? :)Farnesol

© 2022 - 2024 — McMap. All rights reserved.