Difference between revisions of "Play Sound Multiplatform"

From Lazarus wiki
Jump to navigationJump to search
m (Practice makes perfect)
(17 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 from the lazarus CCR [https://sourceforge.net/p/lazarus-ccr/svn/HEAD/tree/components/playsoundpackage/ 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==
 
==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>
+
 
{$IFDEF LINUX}
+
<syntaxhighlight lang="pascal">
 +
{$IFNDEF WINDOWS}
 
SoundPlayerAsyncProcess:Tasyncprocess;
 
SoundPlayerAsyncProcess:Tasyncprocess;
 
SoundPlayerSyncProcess:Tprocess;
 
SoundPlayerSyncProcess:Tprocess;
Line 22: 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>
+
 
{$IFDEF LINUX}
+
<syntaxhighlight lang="pascal">
CONST // Defined in mmsystem
+
CONST C_UnableToPlay = 'Unable to play ';
 +
{$IFNDEF WINDOWS}
 +
// Defined in mmsystem
 
   SND_SYNC=0;
 
   SND_SYNC=0;
 
   SND_ASYNC=1;
 
   SND_ASYNC=1;
Line 35: 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>
+
 
procedure PlaySound(Const szSoundFilename:String);
+
<syntaxhighlight lang="pascal">
Var
+
procedure PlaySound(const szSoundFilename: string);
   flags:Word;
+
var
   linuxplaycommand:String;
+
   flags: word;
 +
   szNonWindowsPlayCommand: string;
 
begin
 
begin
linuxplaycommand:='';
+
  szNonWindowsPlayCommand := '';
 
{$IFDEF WINDOWS}
 
{$IFDEF WINDOWS}
        If fPlayStyle = psASync then flags:=SND_ASYNC OR SND_NODEFAULT
+
  if fPlayStyle = psASync then
        else flags:=SND_SYNC OR SND_NODEFAULT;
+
    flags := SND_ASYNC or SND_NODEFAULT
        TRY
+
  else
        sndPlaySound(PChar(szSoundFilename:String),flags);
+
    flags := SND_SYNC or SND_NODEFAULT;
        except
+
  try
          ShowMessage('Unable to play ' + szSoundFilename:String);
+
    sndPlaySound(PChar(szSoundFilename), flags);
        end;
+
  except
 +
    On E: Exception do
 +
      E.CreateFmt(C_UnableToPlay +
 +
      '%s Message:%s', [szSoundFilename, E.Message]);
 +
  end;
 
{$ELSE}
 
{$ELSE}
      // How to play in Linux? Use generic Linux commands
+
  // How to play in Linux? Use generic Linux commands
      // Use asyncprocess to play sound as SND_ASYNC
+
  // Use asyncprocess to play sound as SND_ASYNC
 
+
  // Try play
// Try play
+
  if (FindDefaultExecutablePath('play') <> '') then
If (FindDefaultExecutablePath('play') <> '') then linuxplaycommand:='play';
+
    szNonWindowsPlayCommand := 'play -q';
// Try aplay
+
  // Try aplay
If (linuxplaycommand='') then
+
  if (szNonWindowsPlayCommand = '') then
  If (FindDefaultExecutablePath('aplay') <> '') Then linuxplaycommand:='aplay';
+
    if (FindDefaultExecutablePath('aplay') <> '') then
// Try paplay
+
      szNonWindowsPlayCommand := 'aplay -q ';
If (linuxplaycommand='') then
+
  // Try paplay
  If (FindDefaultExecutablePath('paplay') <> '') Then linuxplaycommand:='paplay';
+
  if (szNonWindowsPlayCommand = '') then
// proceed if we managed to find a valid command
+
    if (FindDefaultExecutablePath('paplay') <> '') then
If (linuxplaycommand <> '') then
+
      szNonWindowsPlayCommand := 'paplay';
BEGIN
+
  // Try mplayer
      If fPlayStyle = psASync then
+
  if (szNonWindowsPlayCommand = '') then
      begin
+
    if (FindDefaultExecutablePath('mplayer') <> '') then
            If SoundPlayerAsyncProcess=Nil then SoundPlayerAsyncProcess:=Tasyncprocess.Create(Nil);
+
      szNonWindowsPlayCommand := 'mplayer -really-quiet ';
            SoundPlayerAsyncProcess.CurrentDirectory:=ExtractFileDir(szSoundFilename);
+
  // Try CMus
            SoundPlayerAsyncProcess.Executable:=FindDefaultExecutablePath(linuxplaycommand);
+
  if (szNonWindowsPlayCommand = '') then
            SoundPlayerAsyncProcess.Parameters.Clear;
+
    if (FindDefaultExecutablePath('CMus') <> '') then
            SoundPlayerAsyncProcess.Parameters.Add(szSoundFilename);
+
      szNonWindowsPlayCommand := 'CMus ';
            TRY
+
  // Try pacat
            SoundPlayerAsyncProcess.Execute;
+
  if (szNonWindowsPlayCommand = '') then
            except
+
    if (FindDefaultExecutablePath('pacat') <> '') then
              ShowMessage('Playstyle=paASync: Unable to play ' + szSoundFilename);
+
      szNonWindowsPlayCommand := 'pacat -p ';
            end;
+
  // Try ffplay
      end
+
  if (szNonWindowsPlayCommand = '') then
      else
+
    if (FindDefaultExecutablePath('ffplay') <> '') then
      begin
+
      szNonWindowsPlayCommand := 'ffplay -autoexit -nodisp -loglevel quiet';
          If SoundPlayerSyncProcess=Nil then SoundPlayerSyncProcess:=Tprocess.Create(Nil);
+
  // Try cvlc
          SoundPlayerSyncProcess.CurrentDirectory:=ExtractFileDir(szSoundFilename);
+
  if (szNonWindowsPlayCommand = '') then
          SoundPlayerSyncProcess.Executable:=FindDefaultExecutablePath(linuxplaycommand);
+
    if (FindDefaultExecutablePath('cvlc') <> '') then
          SoundPlayersyncProcess.Parameters.Clear;
+
      szNonWindowsPlayCommand := 'cvlc -q --play-and-exit ';
          SoundPlayerSyncProcess.Parameters.Add(szSoundFilename);
+
  // Try canberra-gtk-play
          TRY
+
  if (szNonWindowsPlayCommand = '') then
          SoundPlayerSyncProcess.Execute;
+
    if (FindDefaultExecutablePath('canberra-gtk-play') <> '') then
          SoundPlayersyncProcess.WaitOnExit;
+
      szNonWindowsPlayCommand := 'canberra-gtk-play -c never -f ';
          except
+
  // Try Macintosh command?
            ShowMessage('Playstyle=paSync: Unable to play ' + szSoundFilename);
+
  if (szNonWindowsPlayCommand = '') then
          end;
+
    if (FindDefaultExecutablePath('afplay') <> '') then
      end;
+
      szNonWindowsPlayCommand := 'afplay';
END;
+
  // 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}
 
{$ENDIF}
 
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}
 
FreeAndNil(SoundPlayerSyncProcess);
 
FreeAndNil(SoundPlayerSyncProcess);
 
FreeAndNil(SoundPlayerAsyncProcess);
 
FreeAndNil(SoundPlayerAsyncProcess);
 +
{$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}