AudioClip Precise Timing and Delay

Hi, I’m trying to create sequence player that will play a series of notes a-g given in arrays. The problem is we need very precise timing to get this to work and sound properly. I’ve got something that works but there are still a few issues:

  1. a slight delay between when the first audio clip in a sequence is played and the second. However, after that the 3rd and 4th all play without delay.
  2. over time things seem to eventually skew away from the timing when played against a metronome track

The audio files are 48000 Hz MPEG files and the platform is iOS and Android

Thanks for any help in advance

This is the sequencer’s update function:

    void Update()
	{
	
		if (!currentlyPlaying) {
			return;
		}
		
		//Get Music Time
		float time = AudioManager.MusicTime();
		Sequence sequence = sequences[sequenceIndex];
				
		//For each player
		for (int i = 0; i < sequence.tracks.Length; i++) {
			
			SequenceTrack track = sequence.tracks*;*
  •  	//Apply notes from another track if the current track is empty. Ensures that all 4 tracks are always played.*
    
  •  	//Have to check each track in case the players changed from the default instruments.*
    
  •  	if (track.notes.Count <= 0 && !testGui) {*
    
  •  		for (int k = 0; k < sequence.tracks.Length; k++) {*
    
  •  			if (sequence.tracks[k].notes.Count > 0) {*
    
  •  				track.notes = sequence.tracks[k].notes;*
    
  •  				break;*
    
  •  			}* 
    
  •  		}*
    
  •  	}*
    
  •  	//Skip this track if it is invalid or not filled with notes*
    
  •  	if (track.notes.Count <= 0 || track.mapIndex < 0 || track.mapIndex >= sequenceMaps.Length) {*
    
  •  		continue;*
    
  •  	}*
    
  •  	SequenceMap map = sequenceMaps[track.mapIndex];*
    
  •  	//Find the current interval*
    
  •  	SequenceTrackInterval interval = null;*
    
  •  	for (int j = 0; j < map.intervals.Length; j++) {*
    
  •  		if (time >= map.intervals[j].start && time < map.intervals[j].finish) {*
    
  •  			interval = map.intervals[j];*
    
  •  			break;*
    
  •  		}*
    
  •  	}*
    
  •  	//Continue to next track if we didn't find a valid interval*
    
  •  	if (interval == null) {*
    
  •  		continue;*
    
  •  	}*
    
  •  	//Set first note at start of next interval if we're not inside the interval yet*
    
  •  	if (track.noteTimer < interval.start) {*
    
  •  		track.noteTimer = interval.start;*
    
  •  	}*
    
  •  	time = AudioManager.MusicTime();*
    
  •  	//Get Next note time*
    
  •  	float timeTillNextNote = track.noteTimer - time;*
    
  •  	//Schedule next note to play if we're within a certain time interval of it*
    
  •  	if (timeTillNextNote < 1.0f) {*
    
  •  		//Get the next note for this track*
    
  •  		string note = track.notes[track.noteCounter] as string;*
    

//These calls eventually call the PlayNote function below

  •  		if (timeTillNextNote <= 0) {*
    
  •  			AudioManager.PlayNoteUsingInstrument(track.instrument, note);*
    
  •  		} else {*
    
  •  			AudioManager.PlayNoteUsingInstrument(track.instrument, note, timeTillNextNote);*
    
  •  		}*
    
  •  		float noteInterval = AudioManager.InstrumentIntervalForNote(track.instrument, note);*
    
  •  		track.noteTimer += noteInterval;*
    
  •  		track.noteCounter = (track.noteCounter + 1) % track.notes.Count;*
    
  •  	}*
    
  •  }*
    
  •  //Check if we've looped around or stopped playing*
    
  •  if (time < currentPlayTime || !AudioManager.IsPlaying()) {			*
    
  •  	currentlyPlaying = false;*
    
  •  	AudioManager.PopMusic();*
    
  •  }*
    
  •  currentPlayTime = time;*
    
  • }*

//Delay given in seconds

  • static public void PlayNote(AudioClip clip, float delay)*
  • {*

_ ulong delayInSamples = (ulong)Mathf.RoundToInt(clip.frequency * delay);_

  •  AudioSource source = null;*
    
  •  //Get an unused audio source*
    
  •  if (sharedInstance.audioSourceQueue.Count > 0) {*
    
  •  	source = sharedInstance.audioSourceQueue.Dequeue();*
    
  •  } else {*
    
  •  	//Create a new source if there are no audio sources available	*
    
  •  	source = sharedInstance.gameObject.AddComponent<AudioSource>();*
    
  •  }*
    
  •  if (source.isPlaying) {*
    
  •  	Debug.LogWarning("Playing on source that is already playing");*
    
  •  }*
    
  •  source.clip = clip;*
    
  •  source.Play(delayInSamples);*
    
  •  //Add source to IsPlaying Queue*
    
  •  sharedInstance.isPlayingQueue.Enqueue(source);*
    
  • }*

I’ve personally noticed to give your scene about 1-2 seconds to fully load up to play audio or you get the symptom your getting now. An easy way to do this is to do this:

private bool sceneNotStarted = true;

private void Start(){
     invoke("sceneStarted",1f);
}

private void sceneStarted(){
     sceneNotStarted = false;
}

private void Update(){
     if(sceneNotStarted) return;
     //Your Code Here.....
}