Recent

Author Topic: PlaySound doesn't play sound from resource  (Read 7919 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: 1572
    • 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: 1572
    • 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: 13353
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: 1572
    • 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: 13353
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: 1572
    • 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: 18729
  • To Europe: simply sell USA bonds: dollar collapses
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.
If Europe sells their USA bonds the USD will collapse. Europe can affort that given average state debts. The USA can't affort that. Just an advice...

 

TinyPortal © 2005-2018