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:
- 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.
- 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);*
-
}*