Yesterday I came across the nice playsoundpackage in lazarus-ccr and adapted it for my updated port of TurboPower VisualPlanIt.
I saw, however, that there are cases where it does not work correctly in non-windows systems: The PlaySound routine looks for an executable in GetNonWindowsExecutable and finds "aplay -q" on my Mint system. This string is passed to "FindDefaultExecutablePath" which, however, returns an empty string in this case because a commandline parameter is included (-q) - a file "aplay -q" simply does not exist while a file "aplay" does. So what is missing is a separation of the string into an executable and optional parameters which can be done by means of a stringlist:
var
L: TStrings;
...
if (fPlayCommand <> '') then
begin
// Since the playcommand found above can contain parameters we must
// separate executable and parameters.
L := TStringList.Create; // wp: added from here...
try
L.Delimiter := ' ';
L.DelimitedText := fPlayCommand; // ... to here
if fPlayStyle = psAsync then
begin
if SoundPlayerAsyncProcess = nil then
SoundPlayerAsyncProcess := TAsyncProcess.Create(nil);
SoundPlayerAsyncProcess.CurrentDirectory := ExtractFileDir(szSoundFilename);
SoundPlayerAsyncProcess.Executable := FindDefaultExecutablePath(L[0]); // wp: use L[0] here
SoundPlayerAsyncProcess.Parameters.Clear;
for i:=1 to L.Count-1 do // wp: added
SoundPlayerAsyncProcess.Parameters.Add(L[i]); // wp: added
SoundPlayerAsyncProcess.Parameters.Add(szSoundFilename);
try
SoundPlayerAsyncProcess.Execute;
except
on E: Exception do
E.CreateFmt('PlayStyle=psAsync: ' + 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(L[0]); // wp: use L[0] here
SoundPlayersyncProcess.Parameters.Clear;
for i:=1 to L.Count-1 do // wp: added
SoundPlayerSyncProcess.Parameters.Add(L[i]); // wp: added
SoundPlayerSyncProcess.Parameters.Add(szSoundFilename);
try
SoundPlayerSyncProcess.Execute;
SoundPlayersyncProcess.WaitOnExit;
except
On E: Exception do
E.CreateFmt('PlayStyle = psSync: ' + C_UnableToPlay +
'%s Message:%s', [szSoundFilename, E.Message]);
end;
end;
finally
L.Free; // wp: added
end;
With these additions sound plays fine on Linux Mint. Without it, there is an exception of TProcess saying "Cannot execute an empty command line" - I wonder if that package ever worked correctly.
Another issue is that unit LazFileUtils is found missing on Laz trunk.
Another bug is in StopSound which requires an integer parameter in the call to process.Terminate:
if SoundPlayerSyncProcess <> nil then SoundPlayerSyncProcess.Terminate(1); // any number would be ok
if SoundPlayerAsyncProcess <> nil then SoundPlayerAsyncProcess.Terminate(1);
The demo program has two small issues which may cause new users to turn away: It contains a hard-coded sound file on the author's harddisk. And the property "Playcommand" is not empty and thus overrides the automatic detection of the player software in Linux - an empty string would work fine.
I could fix these issue myself, but since this package is relatively new I am hesitant because its author could still be around here - and maybe there's something behind this code which I do not know.
In the attachment, there's a patch with all modifications (except for the demo).
[EDIT]
BTW: If the author reads this: Why do you make this a component and not a simple procedure? A procedure would be a 1-liner
PlaySound(filename, psSync);
while a component always requires 2-3 lines
PlaySound1.SoundFile := filename;
PlaySound1.PlayStyle := psSync; // could be dropped in case of psAsync
PlaySound1.Execute;