Audio loop calculation and execution

Hi to everyone guys !!!
I’ve just a thing to do but I’m not sure I did it in the best way: I’ve to play a single sound effect for different time lengths by looping the central part of the sound. This operation must be done in parallel with others operations or animations of various GameObjects in the scene.

There are 2 ways to do this:

  1. having 3 different files to combine
  2. having a single files to loop seeking the position of audio at need

My solution to way 1 (C# code) is:

using UnityEngine;
using System.Collections;

public class Loop3SoundsPlayer : MonoBehaviour {

   // the array with the 3 files to play
	public AudioClip[] sounds = new AudioClip [3];
	// final length of audio
   public float finalSoundLength;
	
	// the length the loop must have to achieve the final sound length
	private float loopLength;
	// starting time of sound playing
	private float startTime;
	// flag to know if we need to continue to calculate the sound playing time
	private bool soundPlaying = false;
	
	void Start () {
		loopLength = finalSoundLength - (sounds[0].length + sounds[2].length);
		startTime = Time.time;
	} // Start
	
	void Update () {
		if (soundPlaying) {
			Debug.Log (Time.time - startTime);
		} // if
	} // Update
	
	// called from another controller to start playing the sound
	public void playSound () {
		startTime = Time.time;
		if (audio) {
			playSoundCoroutineStart ();
		} // if
	} // playSound

	private void playSoundCoroutineStart () {
		audio.clip = sounds[0];
		audio.loop = false;
		soundPlaying = true;
		audio.Play ();
		Invoke ("playSoundCoroutineLoop", sounds[0].length);
	} // playSoundCoroutineStart
	
	private void playSoundCoroutineLoop () {
		audio.clip = sounds[1];
		audio.loop = true;
		audio.Play ();
		Invoke ("playSoundCoroutineEnd", loopLength);
	} // playSoundCoroutineLoop

	private void playSoundCoroutineEnd () {
		audio.clip = sounds[2];
		audio.loop = false;
		audio.Play ();
		Invoke ("stopTimer", sounds[2].length);
	} // playSoundCoroutineEnd

	private void stopTimer () {
		soundPlaying = false;
	} // stopTimer
	
} // Loop3SoundsPlayer

the previous controller must be used in couple with this one:

using UnityEngine;
using System.Collections;

public class MoveMe3 : MonoBehaviour {
	
	public Loop3SoundsPlayer lsp;
	
	private bool start = false;

	void Update () {
		if (Input.GetKey (KeyCode.Space)) {
			start = true;
			lsp.playSound ();			
		} // if
		if (start) {
			transform.localPosition += new Vector3 (0.1f, 0f, 0f);
			Invoke ("stopMe", lsp.finalSoundLength);
		} // if
	} // Update
	
	private void stopMe () {
		start = false;
	} // stopMe
	
} // MoveMe3

The effect is that, after pressing space, the GameObject will start to move and the sound will be played. The duration of GameObject movement is linked to the duration of the sound effect. as you can see the sound effect duration is precise by the order of 0.1 secs but I need it with a precision of 0.001 secs !!! My first try was to use a while(true) loop but all won’t work 'cause it wasn’t used as a thread. I know that the “Invoke” are not reliable because they are closely linked to the framerate but the code I’ve shown you was the best solution I was able to think.

For the second way I’ve tried a similar approach by using “AudioSource.time” variable but it doesn’t seems to work.
I tried this piece of code but the audio will always start form its zero position:

using UnityEngine;
using System.Collections;

public class SeekSoundPlaybackPosition : MonoBehaviour {
	
	void Update () {
		if (Input.GetKey (KeyCode.Space)) {
			playSound ();			
		} // if
//		Debug.Log ("audio time = " + audio.time);
	} // Update
	
	private void playSound () {
		if (audio) {
			audio.time = 1.74f;
			Debug.Log ("audio time = " + audio.time);
//			audio.Play ();
		} // if
	} // playSound
	
} // SeekSoundPlaybackPosition

:sweat_smile:
It’s really probable that I’m missing or mistaking something, so… could you be so gentle to help me?

About the first way I’ve lots of doubts about it also if it seems to work correctly.

Please, feel free to comment and post your ideas or alternative solutions.

THANKS A LOT GUYS !!! :smile:

ehm…

audio.time = 1.74f;

is just the AudioSource.time got by the audio controller in GameObject. :wink:

Sorry to everyone but I found a real great problem in the code I wrote: with a very particular combination of sound parts lengths and “finalSoundLength” value, the algorithm doesn’t seems to work. The played sound in not the one I tried to have.

I’ve also tried this script:

using UnityEngine;
using System.Collections;

public class Loop3SoundsPlayerWhile : MonoBehaviour {
	
	public AudioClip[] sounds = new AudioClip [3];
	public float finalSoundLength;
	
	protected bool soundPlaying = false;	
	private float loopLength;
	private float startTime;
	
	void Start () {
		loopLength = finalSoundLength - (sounds[0].length + sounds[2].length);
		startTime = Time.time;
	} // Start
	
	void Update () {
		if (soundPlaying) {
			Debug.Log (Time.time - startTime);
		} // if
	} // Update
	
	public void playSound () {
		startTime = Time.time;
		if (audio) {
			StartCoroutine (playSoundCoroutine ());
		} // if
	} // playSound

	private IEnumerator playSoundCoroutine () {
		audio.clip = sounds[0];
		audio.loop = false;
		soundPlaying = true;
		audio.Play ();
		while (audio.isPlaying) { } // while
		audio.clip = sounds[1];
		float currentLoopTime = 0f;
		while (true) {
			if (!audio.isPlaying) {
				if (currentLoopTime < loopLength) {
					audio.Play ();
					currentLoopTime += sounds[1].length;
				} else {
					break;
				} // if-else
			} // if
		} // while		
		audio.clip = sounds[2];
		audio.Play ();
		soundPlaying = false;
      yield return new WaitForSeconds (0.001f);
	} // playSoundCoroutine
	
} // Loop3SoundsPlayerWhile

and the final sound is as I want but it doesn’t work as a thread so the execution will be stopped until the 2 while cycles finish.

I also tried to use

public void playSound () {
	startTime = Time.time;
	if (audio) {
		Invoke ("playSoundCoroutine", 0.001f);
	} // if
} // playSound

but it doesn’t seems to work like the previous.

I really don’t know how to proceed !!!

Ok… I’m terribly sorry !!! :frowning:

I know that the way I told you all these things must sound complicated so I prepared a Unity project with an example of all things I said.

I hope that now all could result less complicated.

As I just said, I will appreciate all ideas, comments or alternative solutions and please, fell free to ask me all you want to know about.

THANKS AGAIN TO EVERYONE !!! :smile:

117690–4458–$sounds_loop_tests_382.zip (1.69 MB)

AudioSource.time usage solved: it was my fault.
You can find the solution here !!!

Thanks 10thousands to Eric :slight_smile:

But after some tries I saw that it doesn’t work as I need.

Now let’s try to find a solution to the others problems… I’m working on it too !!!