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.
HitomiTenshi
  • 514
  • 2
  • 6
  • 20

4 Answers4

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;
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 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. – HitomiTenshi May 14 '12 at 01:14
  • 1
    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. – Ken White May 14 '12 at 01:21
  • 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! :D – HitomiTenshi May 14 '12 at 01:24
  • 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*...) – Whiler May 14 '12 at 01:49
  • @KenWhite: I ALSO tested... and it works with my Delphi XE2 and 7x64 – Whiler May 14 '12 at 01:52
  • @KenWhite: did you notice the **RT_** ? ;o) ` RT_RCDATA = System.Types.RT_RCDATA; //MakeIntResource(10);` – Whiler May 14 '12 at 01:54
  • 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`. – Jeroen Wiert Pluimers Dec 18 '13 at 23:34
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.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
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

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

Whiler
  • 7,998
  • 4
  • 32
  • 56
  • You can still add the loop (*SND_LOOP*).. but I'm not sure this is really what you want... – Whiler May 14 '12 at 01:24
  • 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? – Ken White May 14 '12 at 01:26
  • Thanks for your help guys, but my hero Ken White already did the job super well. – HitomiTenshi May 14 '12 at 01:28
  • @KenWhite: I agree... your solution is nicer and deserves the *accepted* ;o) (but mine works also) – Whiler May 14 '12 at 01:30
  • 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? :) – Ken White May 14 '12 at 01:36