Recent

Author Topic: [SOLVED] Form not updating from AVMIDIPLayer completion handler - Focus issues?  (Read 1032 times)

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
FPC trunk r44876
Lazarus trunk r63184
Mojave 10.14.6

AVMIDIPlayer class demo - Works as expected until the midi file finishes playing and the completion handler is called.

Code: Pascal  [Select][+][-]
  1. {$mode objfpc}{$H+}
  2. {$modeswitch objectivec1}
  3. {$linkframework AVFoundation}
  4. {$modeswitch cblocks}
  5. ...
  6. procedure play (completionHandler: tblock); message 'play:';
  7. ...

Code: Pascal  [Select][+][-]
  1. // Executed when the midi file finishes playing
  2. procedure myCompletionHandler;
  3. begin
  4.   MyMidiPlayer.Stop;
  5.   MyMidiPlayer.setCurrentPosition(0);
  6.   WriteLn('Completion handler called');
  7.   Form1.PauseButton.Enabled := False;
  8.   Form1.StopPlayButton.Enabled := False;
  9. end;

Code: Pascal  [Select][+][-]
  1. MyMidiPlayer.play(@myCompletionHandler);

Running the application in a terminal from its application bundle directory to read the WriteLn output.

If I comment out the disabling of the buttons in the completion handler, then the WriteLn happens as soon as the midi file finishes playing. If I don't comment those lines, then nothing happens until I click in the TrackBar pointer at which point the buttons are disabled and then, a few seconds later, the WriteLn output appears.

I originally also had updates to various label captions in the completion handler but they were not being updated. Without any clicking, eventually the WriteLn would appear after between 18 and 25 seconds. Clicking on the form would clear the label captions (not write the new content though) and a few seconds later the WriteLn output would appear.
« Last Edit: May 20, 2020, 09:45:52 am by trev »

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2020
  • Former Delphi 1-7, 10.2 user
I discovered a workaround which enables all the code in my completion handler to execute in realtime.

Curious? See my updated Wiki example. The magic is this:

Code: Pascal  [Select][+][-]
  1. // Update elaspsed seconds
  2. procedure TForm1.ElapsedTimerTimer(Sender: TObject);
  3. begin
  4.    // Stop timer if file not playing
  5.    if(myMidiPlayer.isPlaying = False) then
  6.      begin
  7.        ElapsedTimer.Enabled := False;
  8.        // Workaround to update the button status and labels
  9.        // from myCompletionHandler() - otherwise not updated
  10.        // in real time (up to 30 seconds later!)
  11.        Form1.RateTrackBarClick(RateTrackBar);
  12.      end
  13.    // Otherwise update elapsed seconds
  14.    // and progeess bar position
  15.    else
  16.      begin
  17.        SecondsLabel.Caption := FormatFloat('#', myMidiPlayer.currentPosition)
  18.          + ' of ' + FormatFloat('#', fileDuration)
  19.          + ' seconds';
  20.        ProgressBar.Position := Trunc(myMidiPlayer.currentPosition);
  21.      end;
  22. end;
  23.  
  24. // Workaround to update the button status and labels
  25. // from myCompletionHandler() - otherwise not updated
  26. // in real time (up to 30 seconds later!)
  27. procedure TForm1.RateTrackBarClick(Sender: TObject);
  28. begin
  29.   //RateTrackBar.SetFocus; // causes 1 unfreed memory block of 32 bytes on exit
  30.   RateTrackBar.Update;
  31.   ProgressBar.Update;
  32. end;

RateTrackBar.Update: fixes the button states and label content.
ProgressBar.Update: fixes the progress bar position.

A little weird, but... it works :)

 

TinyPortal © 2005-2018