I am converting a Windows game to FMX 2D. Several audio files for music effects have to play asynchronous. With Windows Mediaplayer and VCL it was running very good. Now with Windows Mediaplayer unexspected C5 errors sometimes occur. Therfore I tried the TMediaplayer from FMX. But this player is not eligable, because the game does not run smoothly. It jerks when music effects are played. It seems the main thread is used. The logic for starting music effects runs in a separate thread. In Windows Mediaplayer it is running very good.
Asynchronous playback of music effects is essential for a game. I cannot understand why a relatively new component is not suitable for this. I haven't found a solution on the internet. Is there any component that offers FMX the appropriate features for this case?
This is a sample program to demonstrate FMX MediaPlayer with Threads:
unit Unit1;
// Demo pgm to demonstrate FMX MediaPlayer using Threads, written by Peter Kloß
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Controls.Presentation, FMX.StdCtrls, FMX.Layouts, FMX.ListBox, FMX.Media;
type
TForm1 = class(TForm)
OpenDialog1: TOpenDialog;
ListBox1: TListBox;
LoadButton: TButton;
PlayButton: TButton;
MoveButton: TButton;
Timer1: TTimer;
procedure LoadButtonClick(Sender: TObject);
procedure PlayButtonClick(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
private
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
type
TMsgRecord = record
Filename : string;
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
ThreadVar
msgPtr : ^TMsgRecord;
function PlayMusic(Parameter: Pointer): Integer;
var
MediaPlayer: TMediaPlayer;
begin
Result := 0;
MediaPlayer := TMediaPlayer.Create(Application);
msgPtr := Parameter;
MediaPlayer.FileName := msgPtr.Filename;
MediaPlayer.Play;
repeat
sleep(5);
Application.ProcessMessages;
until MediaPlayer.State <> TMediaState.Playing;
//MediaPlayer.Free; // leads to C5 error in FMX at end of pgm
FreeMem(msgPtr);
EndThread(0);
end;
procedure TForm1.LoadButtonClick(Sender: TObject);
begin
if OpenDialog1.Execute then
ListBox1.Items.AddStrings(OpenDialog1.Files);
end;
procedure TForm1.PlayButtonClick(Sender: TObject);
var
id: LongWord;
thread: Integer;
msg: ^TMsgRecord;
begin
if ListBox1.ItemIndex < 0 then
exit;
GetMem(msg, Sizeof(TMsgRecord));
msg.Filename := ListBox1.Items[ListBox1.ItemIndex];
thread := BeginThread(nil, 0, Addr(PlayMusic), msg, 0, id);
//CloseHandle(thread);
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
if MoveButton.Tag = 0 then
begin
MoveButton.Position.X := MoveButton.Position.X - 1;
if MoveButton.Position.X = 0 then
MoveButton.Tag := 1;
end
else
begin
MoveButton.Position.X := MoveButton.Position.X + 1;
if MoveButton.Position.X = Form1.Width - MoveButton.Width then
MoveButton.Tag := 0;
end
end;
end.
On Form1 there are 2 buttons. One for loading filenames into Listbox1. And one Play button. When Play button is clicked, a thread is started which creates a MediaPlayer and plays the sound given by parameter filename. To see the influence to the programs main activity there is a MoveButton sliding from left to right and vice versa on Form1. For that Timer1 is used, fired every 15 msecs. One can see (and hear) when several sounds are started and playing parallel. The sound should take some seconds so that overlapping occurs and the negative effect is noticeable.