AVAudioEngine 2 audio files played simultaneously but with a short delay between them doesn't delay the first time but works every time after

Viewed 56

I'm upgrading an old app that was written in Objective C and relied upon openAL (which has been deprecated) to manage the audio. The app is a musical interval ear training app. What it does is play two pitches (sound files) either simultaneously or with a small delay (1.2 seconds). Each sound files last from 4 to 8 seconds so there is always a period where they are heard simultaneously.

To work out how to use AVAudioEngine I created an Objective C iOS app in Xcode 12.5.1 with iOS 14.5 as the deployment target. I added a single button (Play Interval) to the storyboard that fires on touch down the playSound action. My viewController.m file looks like this:

#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AVFAudio/AVFAudio.h>

@interface ViewController ()
{
    AVAudioEngine *_engine;
    AVAudioPlayerNode *_player1;
    AVAudioPlayerNode *_player2;
    AVAudioMixerNode *_mainMixer;
}

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    _engine = [[AVAudioEngine alloc]init];
    _player1 = [[AVAudioPlayerNode alloc]init];
    _player2 = [[AVAudioPlayerNode alloc]init];
    
    [_engine attachNode:_player1];
    [_engine attachNode:_player2];
    
    _mainMixer = [_engine mainMixerNode];
}

- (IBAction)playSound:(id)sender {
    NSString *path1 = [[NSBundle mainBundle] pathForResource:@"PianoC4" ofType:@"mp3"];
    NSURL *fileURL1 = [NSURL URLWithString:path1];
    NSString *path2 = [[NSBundle mainBundle] pathForResource:@"PianoE4" ofType:@"mp3"];
    NSURL *fileURL2 = [NSURL URLWithString:path2];
    AVAudioFile *file1 = [[AVAudioFile alloc]initForReading:fileURL1 error:nil];
    AVAudioFile *file2 = [[AVAudioFile alloc]initForReading:fileURL2 error:nil];
    
    const float kStartDelayTime = 0.025;
    
    AVAudioFormat *outputFormat = [_player1 outputFormatForBus:0];
    AVAudioFramePosition startSampleTime = _player1.lastRenderTime.sampleTime;
    AVAudioTime *startTime1 = [AVAudioTime timeWithSampleTime:(startSampleTime + ((kStartDelayTime + 0.0) * outputFormat.sampleRate)) atRate:outputFormat.sampleRate];
    AVAudioTime *startTime2 = [AVAudioTime timeWithSampleTime:(startSampleTime + ((kStartDelayTime + 1.2) * outputFormat.sampleRate)) atRate:outputFormat.sampleRate];
     
    [_engine connect:_player1 to:_mainMixer format:file1.processingFormat];
    [_player1 scheduleFile:file1 atTime: nil completionHandler:nil];
    
    [_engine connect:_player2 to:_mainMixer format:file2.processingFormat];
    [_player2 scheduleFile:file2 atTime: nil completionHandler:nil];
    
    
    NSError *error;
    [_engine startAndReturnError:&error];
    
    if(error) {
        NSLog(@"engine ERROR!");
    }
    
    
    [_player1 playAtTime:startTime1];
    [_player2 playAtTime:startTime2];
}

@end

The first time the playSound button is tapped the 2 sounds are played simultaneously (no delay between the two sound files). Whereas with all subsequent button taps the second sound file is played with the expected 1.2 seconds delay. I can't figure out why the delay does not occur the first time but does occur all other subsequent times!??

Any help will be greatly appreciated and sorry about the Objective C

0 Answers
Related