Recent

Author Topic: PlaySound doesn't play sound from resource  (Read 3823 times)

karloromic

  • New Member
  • *
  • Posts: 32
PlaySound doesn't play sound from resource
« on: September 25, 2019, 12:36:16 pm »
Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, LResources, MMSystem;
  9.  
  10. type
  11.  
  12.   { TForm1 }
  13.  
  14.   TForm1 = class(TForm)
  15.     Button1: TButton;
  16.     procedure Button1Click(Sender: TObject);
  17.   private
  18.  
  19.   public
  20.  
  21.   end;
  22.  
  23. var
  24.   Form1: TForm1;
  25.  
  26. implementation
  27.  
  28. {$R *.lfm}
  29.  
  30. { TForm1 }
  31.  
  32. procedure TForm1.Button1Click(Sender: TObject);
  33. begin
  34.   PlaySound('ONLINE2', HInstance, SND_RESOURCE);
  35. end;
  36.  
  37. end.
  38.  
  39.  

Example project:
https://ufile.io/xw3w18ai
« Last Edit: September 25, 2019, 12:41:33 pm by karloromic »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: PlaySound doesn't play sound from resource
« Reply #1 on: September 25, 2019, 09:58:08 pm »
Code: Pascal  [Select][+][-]
  1. PlaySound('ONLINE2', HInstance, SND_RESOURCE);

In your project1.lpi file, your "ONLINE2" resource is set to a resource type of "RCDATA":

Code: [Select]
<Resource_0 FileName="audio\online2.wav" Type="RCDATA" ResourceName="ONLINE2"/>
It needs to be set to a resource type of "WAVE" instead, or else PlaySound() will not be able to find it at runtime.

Otherwise, you can manually obtain a memory pointer to the resource data using FindResource()/LoadResource()/LockResource(), and then use SND_MEMORY instead of SND_RESOURCE to play it.
« Last Edit: September 25, 2019, 10:02:05 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

karloromic

  • New Member
  • *
  • Posts: 32
Re: PlaySound doesn't play sound from resource
« Reply #2 on: September 25, 2019, 10:21:30 pm »
Setting resource type "WAVE" instead of "RCDATA" doesnt work as it is automatically corrected on compilation..

Otherwise, you can manually obtain a memory pointer to the resource data using FindResource()/LoadResource()/LockResource(), and then use SND_MEMORY instead of SND_RESOURCE to play it.

Can you give me an simple example of that? Thank you

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: PlaySound doesn't play sound from resource
« Reply #3 on: September 25, 2019, 10:38:51 pm »
Allways trouble with the Windows resource files. Neverending story.

Use the Lazarus resource files. You have to convert your WAV-file (or any other file) to an .lrs file:

lazres sound.lrs ONLINE2.WAV

And then copy the sound.lrs to your source file directory.

And in your unit1 you have to write

Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$I sound.lrs }

One problem less.

Winni

karloromic

  • New Member
  • *
  • Posts: 32
Re: PlaySound doesn't play sound from resource
« Reply #4 on: September 25, 2019, 11:01:12 pm »
Allways trouble with the Windows resource files. Neverending story.

Use the Lazarus resource files. You have to convert your WAV-file (or any other file) to an .lrs file:

lazres sound.lrs ONLINE2.WAV

And then copy the sound.lrs to your source file directory.

And in your unit1 you have to write

Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$I sound.lrs }

One problem less.

Winni

Wow, that solved it! Thanks!
 
And also syntax correction:
Code: Pascal  [Select][+][-]
  1. implementation
  2.  
  3. {$I sound.lrs }

should be used on initialization:

Code: Pascal  [Select][+][-]
  1. initialization
  2. {$I sound.lrs}  

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: PlaySound doesn't play sound from resource
« Reply #5 on: September 26, 2019, 02:45:47 am »
Otherwise, you can manually obtain a memory pointer to the resource data using FindResource()/LoadResource()/LockResource(), and then use SND_MEMORY instead of SND_RESOURCE to play it.

Can you give me an simple example of that?

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   hRes: HRSRC;
  4.   hGlob: HGLOBAL;
  5.   pMem: Pointer;
  6. begin
  7.   hRes := FindResource(HInstance, 'ONLINE2', RT_RCDATA{MAKEINTRESOURCE(10)});
  8.   if hRes = 0 then RaiseLastOSError;
  9.  
  10.   hGlob := LoadResource(HInstance, hRes);
  11.   if hGlob = 0 then RaiseLastOSError;
  12.  
  13.   pMem := LockResource(hGlob);
  14.   if pMem = nil then RaiseLastOSError;
  15.  
  16.   PlaySound(PChar(pMem), 0, SND_MEMORY);
  17. end;
  18.  
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

bmcsoft

  • New Member
  • *
  • Posts: 21
Re: PlaySound doesn't play sound from resource
« Reply #6 on: April 07, 2022, 02:34:46 pm »
What is wrong with this code?

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button3Click(Sender: TObject);
  2. var  r: TLResource;
  3.   Data: string;
  4.   pMem: Pointer;
  5. begin
  6.     r := LazarusResources.Find('queen');
  7.     if r = nil then raise Exception.Create('Resource datafile1 is missing')
  8.                else begin
  9.                     ShowMessage ('found'); // Here's OK!
  10.                     Data := r.Value;
  11.                     pMem := @Data;
  12.                     PlaySound(PChar(pMem), 0, SND_MEMORY); // Here's no sound
  13.                     end;
  14. end;                    

I want to play WAVE directly from resources. This code use LRS-file, compiled with {$I madpcm.lrs}   

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: PlaySound doesn't play sound from resource
« Reply #7 on: April 07, 2022, 03:45:39 pm »
@bmcsoft: Did you try Remy's code? Here is another variant which I tested to work:
Code: Pascal  [Select][+][-]
  1. {$R sound.res}
  2.  
  3. procedure TForm1.Button2Click(Sender: TObject);
  4. var
  5.   resStream: TResourceStream;
  6.   memoryStream: TMemoryStream;
  7. begin
  8.   resStream := TResourceStream.Create(HINSTANCE, 'ALARM01', RT_RCDATA);
  9.   try
  10.     memoryStream := TMemoryStream.Create;
  11.     try
  12.       resStream.Position := 0;
  13.       memoryStream.CopyFrom(resStream, resStream.Size);
  14.       memoryStream.Position := 0;
  15.       PlaySound(PChar(memorystream.memory), 0,SND_MEMORY or SND_ASYNC);
  16.     finally
  17.       memorystream.Free;
  18.     end;
  19.   finally
  20.     resStream.Free;
  21.   end;
  22. end;

The sound.res resource file is created by executing the following line on the command line:
Code: Text  [Select][+][-]
  1. lazres sound.res "C:\Windows\Media\Alarm01.wav"


Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: PlaySound doesn't play sound from resource
« Reply #8 on: April 07, 2022, 05:31:08 pm »
@bmcsoft: Did you try Remy's code? Here is another variant which I tested to work:

The TMemoryStream copy is not necessary, since TResourceStream is a TCustomMemoryStream descendant:

Code: Pascal  [Select][+][-]
  1. {$R sound.res}
  2.  
  3. procedure TForm1.Button2Click(Sender: TObject);
  4. var
  5.   resStream: TResourceStream;
  6. begin
  7.   resStream := TResourceStream.Create(HINSTANCE, 'ALARM01', RT_RCDATA);
  8.   try
  9.     PlaySound(PChar(resStream.Memory), 0, SND_MEMORY or SND_SYNC);
  10.   finally
  11.     resStream.Free;
  12.   end;
  13. end;

Whether you use TMemorySteam or not, using SND_ASYNC in your example is dangerous since you are freeing the audio data from memory before PlaySound() is done playing it. You would have to use SND_SYNC instead, as shown above. Otherwise, to use SND_ASYNC, you have to wait until after playback is finished before freeing the memory.
« Last Edit: April 07, 2022, 05:33:48 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

bmcsoft

  • New Member
  • *
  • Posts: 21
Re: PlaySound doesn't play sound from resource
« Reply #9 on: April 07, 2022, 09:54:27 pm »
Thank you for answers! This forum is necessary to simple users.
My variant of code works fine with
Code: Pascal  [Select][+][-]
  1. begin
  2. Data := r.Value;
  3. pMem := @Data[1];  // bingo!
  4. PlaySound(PChar(pMem), 0, SND_MEMORY); // Now playing fine
  5. end;
because a String is a pointer to a 12-byte structure that contains:
a counter of references to a string (offset -8),
the length of its body in bytes (offset -4),
a pointer to the body of the string (offset 0).
So body of the string has offset +1.

wp

  • Hero Member
  • *****
  • Posts: 11855
Re: PlaySound doesn't play sound from resource
« Reply #10 on: April 07, 2022, 10:43:30 pm »
Yes, of course!

winni

  • Hero Member
  • *****
  • Posts: 3197
Re: PlaySound doesn't play sound from resource
« Reply #11 on: April 07, 2022, 10:47:30 pm »
So body of the string has offset +1.

Since  the end of the 70s


Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1312
    • Lebeau Software
Re: PlaySound doesn't play sound from resource
« Reply #12 on: April 07, 2022, 10:50:45 pm »
My variant of code works fine with

Using a string to hold non-textual binary data is a bad idea.

a pointer to the body of the string (offset 0).

The leading structure of a string does not contain a pointer to the character data.  The character data immediately follows the structure in memory.  Two different things.  Offset 0 into the string is the same memory address as the 1st character of the string.

So body of the string has offset +1.

The leading structure has nothing to do with why the offset of the character data starts at +1.  It is because of backwards compatibility with ShortString, whose length is stored in the character at offset 0 and the 1st character starts at offset 1.  And so, AnsiString (and UnicodeString) access their character data beginning at offset 1 too, making it easier for people to migrate older code to newer string types.
« Last Edit: April 07, 2022, 10:53:32 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

bmcsoft

  • New Member
  • *
  • Posts: 21
Re: PlaySound doesn't play sound from resource
« Reply #13 on: April 08, 2022, 03:38:03 pm »
Using a string to hold non-textual binary data is a bad idea.
Why?
My code is taken from here: https://wiki.freepascal.org/Lazarus_Resources

Thaddy

  • Hero Member
  • *****
  • Posts: 14201
  • Probably until I exterminate Putin.
Re: PlaySound doesn't play sound from resource
« Reply #14 on: April 08, 2022, 03:58:08 pm »
Not everything in the wiki is correct. Remy is right.
I will fix that wiki entry, because it is plain wrong.
Specialize a type, not a var.

 

TinyPortal © 2005-2018