Recent

Author Topic: [SOLVED] NSSound Delegate implementation  (Read 1726 times)

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2032
  • Former Delphi 1-7, 10.2 user
[SOLVED] NSSound Delegate implementation
« on: June 07, 2020, 03:56:59 pm »
Code: Pascal  [Select][+][-]
  1. type
  2.   NSSound = objcclass external (NSObject)
  3.   public  
  4.     ...
  5.     procedure setDelegate(newValue: NSObject); message 'setDelegate:';
  6.     function delegate: NSSoundDelegateProtocol; message 'delegate';    
  7.     ...
  8.   end;
  9.  
  10. NSSoundDelegateProtocol = objcprotocol external name 'NSSoundDelegate' (NSObjectProtocol)
  11.   optional
  12.     procedure sound_didFinishPlaying (sound: NSSound; aBool: ObjCBOOL);
  13.        message 'sound:didFinishPlaying:';
  14.   end;
  15.  
  16. NSSoundFinishedDelegate = objcclass(NSObject)
  17.   public
  18.     procedure didFinishPlaying(Sound: NSSound; FinishedPlaying: Boolean);
  19.        message 'sound:didFinishPlaying:';
  20.   end;
  21.  
  22. implementation
  23.  
  24. var
  25.   SoundFinishedDelegate: NSSoundFinishedDelegate;
  26.  
  27. procedure NSSoundFinishedDelegate.didFinishPlaying(Sound: NSSound; FinishedPlaying: Boolean);
  28. begin
  29.   if(FinishedPlaying) then
  30.      ShowMessage('Sound ' + CFStringToStr(CFStringRef(Sound.Name)) + ' finished');
  31. end;                                            
  32. ...
  33. Initialization
  34.   SoundFinishedDelegate := NSSoundFinishedDelegate.alloc.init;
  35.   Sound.setDelegate(SoundFinishedDelegate);
  36. Finalization
  37.   Sound.setDelegate(Nil);
  38.   SoundFinishedDelegate.release;
  39. end.

Where did I go wrong? All my play/pause/resume procedures work, but my didFinishPlaying procedure never triggers when the sound finishes playing :(
« Last Edit: June 09, 2020, 01:10:29 am by trev »

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: NSSound Delegate implementation
« Reply #1 on: June 07, 2020, 08:07:57 pm »
since you're using initialization and finalization sections, I'm assuming you're trying to use them in the console application?

I did a small UI test and it works just fine. (attached). (The path to the sound is hardcoded! you need to change it in the code!)

From the nature of the playing sounds, there's always a problem of synchronization of events. I.e. "end of sounds" can always be reported from a separate thread.
However, the test shows that "end of sounds" is reported to the main thread. That certainly involves having a running event loops.
And such loop typically doesn't exist, if you're writing a console application.

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2032
  • Former Delphi 1-7, 10.2 user
Re: NSSound Delegate implementation
« Reply #2 on: June 08, 2020, 04:50:31 am »
Thanks for your working example Dmitry.

Despite 8 errors(!) during the compilation, it succeeds and the application runs without issue...

Quote
Compile Project, Target: project1: Success, Errors: 8
Error: <stdin>:1052:10: warning: section "__datacoal_nt" is deprecated
Error: .section __DATA, __datacoal_nt, coalesced
Error: <stdin>:1052:10: note: change section name to "__data"
Error: .section __DATA, __datacoal_nt, coalesced
Error: <stdin>:1092:10: warning: section "__datacoal_nt" is deprecated
Error: .section __DATA, __datacoal_nt, coalesced
Error: <stdin>:1092:10: note: change section name to "__data"
Error: .section __DATA, __datacoal_nt, coalesced

It was in fact a GUI application, not a console application. The initialisation/finalization clauses seemed the way to go, but obviously not! I've now modified it along the lines of your example and... it works!

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: NSSound Delegate implementation
« Reply #3 on: June 08, 2020, 01:07:58 pm »
It was in fact a GUI application, not a console application.
here's another thing to try.

In your initial example, class NSSoundFinishedDelegate does implement the method 'sound:didFinishPlaying:', but doesn't implement the protocol. (even though the protocol consists of a single method).

Try your original code, but declare the delegate as implementing the protocol:
Code: Pascal  [Select][+][-]
  1. NSSoundFinishedDelegate = objcclass(NSObject, NSSoundDelegateProtocol)
  2.   public
  3.     procedure sound_didFinishPlaying(Sound: NSSound; FinishedPlaying: Boolean);
  4.   end;
  5.  

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2032
  • Former Delphi 1-7, 10.2 user
Re: NSSound Delegate implementation
« Reply #4 on: June 08, 2020, 02:27:32 pm »
That works if I move Sound.setDelegate(SoundFinishedDelegate); from the Initialisation clause to the play procedure.

skalogryz

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2770
    • havefunsoft.com
Re: NSSound Delegate implementation
« Reply #5 on: June 08, 2020, 02:56:28 pm »
That works if I move Sound.setDelegate(SoundFinishedDelegate); from the Initialisation clause to the play procedure.
when does Sound.initWithXXX occurs? before setting the delegate of after?

trev

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 2032
  • Former Delphi 1-7, 10.2 user
Re: NSSound Delegate implementation
« Reply #6 on: June 08, 2020, 03:34:50 pm »
Code: Pascal  [Select][+][-]
  1. procedure TForm1.PlayButtonClick(Sender: TObject);
  2. var
  3.   audioFilePath: NSString;
  4.   status: Boolean;
  5. begin
  6.   audioFilePath := NSStringUTF8('/Applications/iPhoto.app/Contents/Resources/Music/Barbeque Blues.m4a');
  7.   Sound := NSSound.alloc.initWithContentsOfFile_byReference(audioFilePath, True); // File system file
  8.  
  9.   Sound.setDelegate(SoundFinishedDelegate);
  10.  
  11.   status := Sound.play;
  12.   if(status) then
  13.     //
  14.   else
  15.     ShowMessage('Not OK');
  16. end;
  17.  

Before ... I just tried after and that doesn't trigger the delegate. Above code works.

 

TinyPortal © 2005-2018