Get AVAudioSequencer to notify completion

Hello,

I have the following code to get an AVAudioSequencer playing a MIDI file:

  AVAudioEngine        *engine;
  AVAudioUnitSampler  *sampler;
  AVAudioSequencer  *sequencer;

  engine = [[AVAudioEngine alloc] init];
  sampler = [[AVAudioUnitSampler alloc] init];
  [engine attachNode:sampler];
  [engine connect:sampler to:engine.mainMixerNode format:nil];
  NSURL *url = [NSBundle.mainBundle URLForResource:@"mysamples" withExtension:@"sf2"];
  [sampler loadSoundBankInstrumentAtURL:url program:0
             bankMSB:(UInt8)kAUSampler_DefaultMelodicBankMSB
             bankLSB:(UInt8)kAUSampler_DefaultBankLSB error:&err];
  
  sequencer = [[AVAudioSequencer alloc] initWithAudioEngine:engine];
  [engine startAndReturnError:&err];
  
  [AVAudioSession.sharedInstance setCategory:AVAudioSessionCategoryPlayback error:&err];
  [sequencer loadFromData:someMidiData options:AVMusicSequenceLoadSMF_PreserveTracks error:&err];
  [sequencer startAndReturnError:&err];

It is fairly straightforward code and it works.


The point is that I need to be notified when the playback completes and I don't know how to achieve this.

The best thing I have thought so far is polling the sequnecer's isPolling property.

I know some objects can be connected to an AudioCompletionHandler, but I don't think it's the case of the sequencer, since it does not inherit from AVAudioNode.


Any help is appreciated.

Maybe a little late but here is a workaround Once the data (or URL ) is loaded I determine the seconds in the tracks; I then issue a Timer at the computed time which call a delegate method. The delegate triggers a method to deactivate the timer

-(NSTimeInterval)totalLengthInSeconds {

NSTimeInterval result = 0.5;
for(AVMusicTrack *track in _audioSequencer.tracks)  {
    result += track.lengthInSeconds;
}
return result;

}

-(void) example {

[_audioSequencer prepareToPlay]; NSTimeInterval totalLengthInSeconds = [self totalLengthInSeconds]; [_audioSequencer startAndReturnError:&error]; _audioSequencer.currentPositionInSeconds = 0;

_sequencerTimer = [NSTimer scheduledTimerWithTimeInterval:totalLengthInSeconds repeats:NO block:^(NSTimer * _Nonnull timer) { [self.delegate midiPlayerDidEnd]; }]; }

BlockQuote

Replace the previous reply:

Once the data (or URL ) is loaded, I determine the seconds in the tracks; I then issue a Timer at the computed time which call a delegate method. The delegate triggers a method to deactivate the timer

> -(NSTimeInterval)totalLengthInSeconds {
  NSTimeInterval result = 0.5;
  for(AVMusicTrack *track in _audioSequencer.tracks)  {
    result = MAX( result, track.lengthInSeconds);
 }
 return result;
}

-(void) example {
  [_audioSequencer prepareToPlay];
  NSTimeInterval totalLengthInSeconds = [self totalLengthInSeconds];
  [_audioSequencer startAndReturnError:&error];
  _audioSequencer.currentPositionInSeconds = 0;
  _sequencerTimer = [NSTimer 
scheduledTimerWithTimeInterval:totalLengthInSeconds repeats:NO block:^(NSTimer * _Nonnull timer) {
    [self.delegate midiPlayerDidEnd]; 
  }]; 
}
``

Get AVAudioSequencer to notify completion
 
 
Q