FMX and TMediaplayer playing several audio files

353 views Asked by At

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.

0

There are 0 answers