Difference between revisions of "Play Sound Multiplatform"

From Lazarus wiki
Jump to navigationJump to search
(Changed {$IFDEF LINUX} to {$IFNDEF WINDOWS} - who knows? It might work in OSX..)
(11 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
==Summary==
 
==Summary==
*The object is to play a simple WAV sound both in Windows and Linux (Sync and ASync)
+
 
*There are lots of libraries to do this in a complicated way, but this code should suffice for simple use
+
* The object is to play a simple WAV sound both in Windows and Linux (Sync and ASync)
 +
* There are lots of libraries to do this in a complicated way, but this code should suffice for simple use
 +
 
 
===Download Component===
 
===Download Component===
Download from the lazarus CCR [https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/ here]
+
 
 +
Download from the lazarus CCR [https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/playsoundpackage/ here] (playsoundpackage)
 +
 
 
===Installation of component===
 
===Installation of component===
*Download the 'playsoundpackage' package from the Lazarus CCR repository and copy the folder to a folder off your lazarus components folder
+
 
*Install the package (open it, Compile then Install it) and TPlaysound will appear on your 'LazControls' components tab
+
*Download all the 'playsoundpackage' package files from the Lazarus CCR repository and copy the whole folder structure to an empty folder off your lazarus components folder
 +
*Install the package (open it, Compile then Install it) and '''TPlaysound''' will appear on your 'LazControls' components tab
 
*Drop onto a form, set properties and you are good to go
 
*Drop onto a form, set properties and you are good to go
 +
*PlayCommand property is populated automatically by testing which will work with your system.
 
*Opening the demo application will give you a good idea how to set the additional properties and use the component
 
*Opening the demo application will give you a good idea how to set the additional properties and use the component
 +
 
===Version===
 
===Version===
*As reported in the IDE.  Initial version is 0.0.1
+
 
 +
*As reported in the IDE.  Initial version is 0.0.2
 +
 
 
===License===
 
===License===
 +
 
*LGPLv2
 
*LGPLv2
 +
 
==Code==
 
==Code==
 +
 
*Here is the Uses clause in the Implementation section:
 
*Here is the Uses clause in the Implementation section:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
..other units..
 
..other units..
FileUtil{$IFDEF WINDOWS},mmsystem{$ELSE},asyncprocess,process{$ENDIF}
+
FileUtil{$IFDEF WINDOWS},mmsystem{$ELSE},asyncprocess,process{$ENDIF},StrUtils
 
..other units..
 
..other units..
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*Declare a type:
 
*Declare a type:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
TPlayStyle = (psAsync,psSync);
 
TPlayStyle = (psAsync,psSync);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*Declare some variables:
 
*Declare some variables:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
{$IFNDEF WINDOWS}
 
{$IFNDEF WINDOWS}
 
SoundPlayerAsyncProcess:Tasyncprocess;
 
SoundPlayerAsyncProcess:Tasyncprocess;
Line 33: Line 50:
 
fPlayStyle:TPlayStyle;
 
fPlayStyle:TPlayStyle;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*And a worker function:
 
*And a worker function:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
procedure PlaySound(Const szSoundFilename:String);
 
procedure PlaySound(Const szSoundFilename:String);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*And a couple of constants:
 
*And a couple of constants:
<syntaxhighlight>
+
 
CONST
+
<syntaxhighlight lang="pascal">
C_UnableToPlay = 'Unable to play ';
+
CONST C_UnableToPlay = 'Unable to play ';
 
{$IFNDEF WINDOWS}
 
{$IFNDEF WINDOWS}
 
  // Defined in mmsystem
 
  // Defined in mmsystem
Line 48: Line 68:
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*Now you are good to go:
 
*Now you are good to go:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
fPlayStyle := psASync;
 
fPlayStyle := psASync;
 
fPathToSoundFile:='mysound.wav';
 
fPathToSoundFile:='mysound.wav';
 
If FileExistsUTF8(fPathToSoundFile) then PlaySound(fPathToSoundFile);
 
If FileExistsUTF8(fPathToSoundFile) then PlaySound(fPathToSoundFile);
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*Here's the PlaySound procedure
 
*Here's the PlaySound procedure
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
procedure PlaySound(const szSoundFilename: string);
 
procedure PlaySound(const szSoundFilename: string);
 
var
 
var
Line 79: Line 103:
 
   // Try play
 
   // Try play
 
   if (FindDefaultExecutablePath('play') <> '') then
 
   if (FindDefaultExecutablePath('play') <> '') then
     szNonWindowsPlayCommand := 'play';
+
     szNonWindowsPlayCommand := 'play -q';
 
   // Try aplay
 
   // Try aplay
 
   if (szNonWindowsPlayCommand = '') then
 
   if (szNonWindowsPlayCommand = '') then
Line 103: Line 127:
 
   if (szNonWindowsPlayCommand = '') then
 
   if (szNonWindowsPlayCommand = '') then
 
     if (FindDefaultExecutablePath('ffplay') <> '') then
 
     if (FindDefaultExecutablePath('ffplay') <> '') then
       szNonWindowsPlayCommand := 'ffplay -autoexit -nodisp ';
+
       szNonWindowsPlayCommand := 'ffplay -autoexit -nodisp -loglevel quiet';
 
   // Try cvlc
 
   // Try cvlc
 
   if (szNonWindowsPlayCommand = '') then
 
   if (szNonWindowsPlayCommand = '') then
Line 116: Line 140:
 
     if (FindDefaultExecutablePath('afplay') <> '') then
 
     if (FindDefaultExecutablePath('afplay') <> '') then
 
       szNonWindowsPlayCommand := 'afplay';
 
       szNonWindowsPlayCommand := 'afplay';
 +
  // Try mpg321
 +
  if (szNonWindowsPlayCommand = '') then
 +
    if (FindDefaultExecutablePath('mpg321') <> '') then
 +
      szNonWindowsPlayCommand := 'mpg321 -q';
 
   // proceed if we managed to find a valid command
 
   // proceed if we managed to find a valid command
 
   if (szNonWindowsPlayCommand <> '') then
 
   if (szNonWindowsPlayCommand <> '') then
Line 125: Line 153:
 
       SoundPlayerAsyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
 
       SoundPlayerAsyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
 
       SoundPlayerAsyncProcess.Executable :=
 
       SoundPlayerAsyncProcess.Executable :=
         FindDefaultExecutablePath(szNonWindowsPlayCommand);
+
         FindDefaultExecutablePath(Copy2Space(szNonWindowsPlayCommand));
 
       SoundPlayerAsyncProcess.Parameters.Clear;
 
       SoundPlayerAsyncProcess.Parameters.Clear;
 
       SoundPlayerAsyncProcess.Parameters.Add(szSoundFilename);
 
       SoundPlayerAsyncProcess.Parameters.Add(szSoundFilename);
Line 142: Line 170:
 
       SoundPlayerSyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
 
       SoundPlayerSyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
 
       SoundPlayerSyncProcess.Executable :=
 
       SoundPlayerSyncProcess.Executable :=
         FindDefaultExecutablePath(szNonWindowsPlayCommand);
+
         FindDefaultExecutablePath(Copy2Space(szNonWindowsPlayCommand));
 
       SoundPlayersyncProcess.Parameters.Clear;
 
       SoundPlayersyncProcess.Parameters.Clear;
 
       SoundPlayerSyncProcess.Parameters.Add(szSoundFilename);
 
       SoundPlayerSyncProcess.Parameters.Add(szSoundFilename);
Line 161: Line 189:
 
end;
 
end;
 
</syntaxhighlight>
 
</syntaxhighlight>
 +
 
*Destroy the process objects in your Destroy procedure:
 
*Destroy the process objects in your Destroy procedure:
<syntaxhighlight>
+
 
 +
<syntaxhighlight lang="pascal">
 
{$IFNDEF WINDOWS}
 
{$IFNDEF WINDOWS}
 
FreeAndNil(SoundPlayerSyncProcess);
 
FreeAndNil(SoundPlayerSyncProcess);
Line 168: Line 198:
 
{$ENDIF}
 
{$ENDIF}
 
</syntaxhighlight>
 
</syntaxhighlight>
<br>
 
----
 
[[minesadorada]]
 
  
 
[[Category:Audio]]
 
[[Category:Audio]]
 +
[[Category:Components]]

Revision as of 20:12, 26 April 2021

Summary

  • The object is to play a simple WAV sound both in Windows and Linux (Sync and ASync)
  • There are lots of libraries to do this in a complicated way, but this code should suffice for simple use

Download Component

Download from the lazarus CCR here (playsoundpackage)

Installation of component

  • Download all the 'playsoundpackage' package files from the Lazarus CCR repository and copy the whole folder structure to an empty folder off your lazarus components folder
  • Install the package (open it, Compile then Install it) and TPlaysound will appear on your 'LazControls' components tab
  • Drop onto a form, set properties and you are good to go
  • PlayCommand property is populated automatically by testing which will work with your system.
  • Opening the demo application will give you a good idea how to set the additional properties and use the component

Version

  • As reported in the IDE. Initial version is 0.0.2

License

  • LGPLv2

Code

  • Here is the Uses clause in the Implementation section:
..other units..
FileUtil{$IFDEF WINDOWS},mmsystem{$ELSE},asyncprocess,process{$ENDIF},StrUtils
..other units..
  • Declare a type:
TPlayStyle = (psAsync,psSync);
  • Declare some variables:
{$IFNDEF WINDOWS}
SoundPlayerAsyncProcess:Tasyncprocess;
SoundPlayerSyncProcess:Tprocess;
{$ENDIF}
fPathToSoundFile:String;
fPlayStyle:TPlayStyle;
  • And a worker function:
procedure PlaySound(Const szSoundFilename:String);
  • And a couple of constants:
CONST C_UnableToPlay = 'Unable to play ';
{$IFNDEF WINDOWS}
 // Defined in mmsystem
  SND_SYNC=0;
  SND_ASYNC=1;
  SND_NODEFAULT=2;
{$ENDIF}
  • Now you are good to go:
fPlayStyle := psASync;
fPathToSoundFile:='mysound.wav';
If FileExistsUTF8(fPathToSoundFile) then PlaySound(fPathToSoundFile);
  • Here's the PlaySound procedure
procedure PlaySound(const szSoundFilename: string);
var
  flags: word;
  szNonWindowsPlayCommand: string;
begin
  szNonWindowsPlayCommand := '';
{$IFDEF WINDOWS}
  if fPlayStyle = psASync then
    flags := SND_ASYNC or SND_NODEFAULT
  else
    flags := SND_SYNC or SND_NODEFAULT;
  try
    sndPlaySound(PChar(szSoundFilename), flags);
  except
    On E: Exception do
      E.CreateFmt(C_UnableToPlay +
      '%s Message:%s', [szSoundFilename, E.Message]);
  end;
{$ELSE}
  // How to play in Linux? Use generic Linux commands
  // Use asyncprocess to play sound as SND_ASYNC
  // Try play
  if (FindDefaultExecutablePath('play') <> '') then
    szNonWindowsPlayCommand := 'play -q';
  // Try aplay
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('aplay') <> '') then
      szNonWindowsPlayCommand := 'aplay -q ';
  // Try paplay
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('paplay') <> '') then
      szNonWindowsPlayCommand := 'paplay';
  // Try mplayer
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('mplayer') <> '') then
      szNonWindowsPlayCommand := 'mplayer -really-quiet ';
  // Try CMus
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('CMus') <> '') then
      szNonWindowsPlayCommand := 'CMus ';
  // Try pacat
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('pacat') <> '') then
      szNonWindowsPlayCommand := 'pacat -p ';
  // Try ffplay
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('ffplay') <> '') then
      szNonWindowsPlayCommand := 'ffplay -autoexit -nodisp -loglevel quiet';
  // Try cvlc
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('cvlc') <> '') then
      szNonWindowsPlayCommand := 'cvlc -q --play-and-exit ';
  // Try canberra-gtk-play
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('canberra-gtk-play') <> '') then
      szNonWindowsPlayCommand := 'canberra-gtk-play -c never -f ';
  // Try Macintosh command?
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('afplay') <> '') then
      szNonWindowsPlayCommand := 'afplay';
  // Try mpg321
  if (szNonWindowsPlayCommand = '') then
    if (FindDefaultExecutablePath('mpg321') <> '') then
      szNonWindowsPlayCommand := 'mpg321 -q';
  // proceed if we managed to find a valid command
  if (szNonWindowsPlayCommand <> '') then
  begin
    if fPlayStyle = psASync then
    begin
      if SoundPlayerAsyncProcess = nil then
        SoundPlayerAsyncProcess := Tasyncprocess.Create(nil);
      SoundPlayerAsyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
      SoundPlayerAsyncProcess.Executable :=
        FindDefaultExecutablePath(Copy2Space(szNonWindowsPlayCommand));
      SoundPlayerAsyncProcess.Parameters.Clear;
      SoundPlayerAsyncProcess.Parameters.Add(szSoundFilename);
      try
        SoundPlayerAsyncProcess.Execute;
      except
        On E: Exception do
          E.CreateFmt('Playstyle=paASync: ' + C_UnableToPlay +
            '%s Message:%s', [szSoundFilename, E.Message]);
      end;
    end
    else
    begin
      if SoundPlayerSyncProcess = nil then
        SoundPlayerSyncProcess := Tprocess.Create(nil);
      SoundPlayerSyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
      SoundPlayerSyncProcess.Executable :=
        FindDefaultExecutablePath(Copy2Space(szNonWindowsPlayCommand));
      SoundPlayersyncProcess.Parameters.Clear;
      SoundPlayerSyncProcess.Parameters.Add(szSoundFilename);
      try
        SoundPlayerSyncProcess.Execute;
        SoundPlayersyncProcess.WaitOnExit;
      except
        On E: Exception do
          E.CreateFmt('Playstyle=paSync: ' + C_UnableToPlay +
            '%s Message:%s', [szSoundFilename, E.Message]);
      end;
    end;
  end
  else
    raise Exception.CreateFmt('The play command %s does not work on your system',
      [szNonWindowsPlayCommand]);
{$ENDIF}
end;
  • Destroy the process objects in your Destroy procedure:
{$IFNDEF WINDOWS}
FreeAndNil(SoundPlayerSyncProcess);
FreeAndNil(SoundPlayerAsyncProcess);
{$ENDIF}