Unable to play multiple wav files

I’m struggling to get multiple wav files to be loaded from persistant data are and played one after another.
I did have another thread on this which got out of control, so thought I’d try again afresh with a simple example.

The filenames for the clips are in a List. But for the purpose of this test I’m just using an index x to find files test1, test2, test3.wav in persistant data path. They need to be there, as I create them earlier.

I’m initially checking if I need to load a file using WWW in ReplayAllSOunds. If I do, I’ll start loading it.

Then I’ll check if it is loaded.
If it is and thats the first time I check I’ll start playing it and set a flag

What I cant work out is how to know it has finished playing it, and how to get my ReplayAllSounds method should move on to the next file. I’ve tried yield. I’ve tried isPlaying(). I’ve tried using the time as per the current example. Nothing seems to work. It plays the first clip and thats it.

If someone could get this simple example working I’d be very grateful. I’m made the example code as simple as I possibly can, it just needs someone who knows how to tell when its playing and when its not.

Thank You in advanace. I’m sure its fairly simple, but I’m new to all this and struggling badly with this.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text;

using System.Text.RegularExpressions;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;

using UnityEngine.Networking;
public class TestSound : MonoBehaviour {
    public GameObject textBox;
    public AudioSource g03AudioSource;
    bool playingSoundFile = false;
    bool loadingAudioClip = false;
    bool needToLoadAudioclip = true;
    bool needToCheckForAudioclip = false;
    int clipCount = 2;
    int clipIndex = 0;
    float progress;
    UnityWebRequest www;
    // Use this for initialization
    void Start () {
        textBox.GetComponent<Text>().text = Application.persistentDataPath;

    }

    // Update is called once per frame
    void Update () {
        ReplayAllSounds ();
        checkIfSoundFileLoaded ();
    }
    // Replay All SOunds
    public void ReplayAllSounds(){
        if (clipIndex <= clipCount && playingSoundFile == false && loadingAudioClip == false && needToLoadAudioclip == true){
            textBox.GetComponent<Text> ().text = Application.persistentDataPath + "/test" + clipIndex + ".wav";
            loadingAudioClip = true;
            needToCheckForAudioclip = true;
            playingSoundFile = false;
            www = UnityWebRequestMultimedia.GetAudioClip (Application.persistentDataPath + "/test" + clipIndex + ".wav", AudioType.WAV);
            www.SendWebRequest ();

        }

    }

    void checkIfSoundFileLoaded(){
        if (needToCheckForAudioclip == true) {
            if (www.isDone) { // If loaded
                loadingAudioClip = false;
                textBox.GetComponent<Text> ().text = "ISLOADED " + clipIndex;
                if (!g03AudioSource.isPlaying) { // If not playing
                        // First time not playing - startplaying
                        if (playingSoundFile == false) {
                            playingSoundFile = true;
                            textBox.GetComponent<Text> ().text = "ISPLAYING " + clipIndex;
                            playingSoundFile = true; //set flag to say playing
                            AudioClip audioClip = DownloadHandlerAudioClip.GetContent (www);
                            g03AudioSource.clip = audioClip;
                            g03AudioSource.Play (); // and play
                    }
                }else
                {
                        progress = Mathf.Clamp01(g03AudioSource.time / g03AudioSource.clip.length);
                        if (progress == 1f)
                        {
                            g03AudioSource.Stop ();
                            www.Abort ();
                        www.Dispose ();
                            playingSoundFile = false;
                            loadingAudioClip = false;
                            needToCheckForAudioclip = false;
                            needToLoadAudioclip = true;
                            clipIndex++; // move on to next one
                        }
                        }
                    }

            }
        }

}

I think I would personally organize things a bit differently.

However, before getting into that, if you write a small test script and play 1 clip from an audio source (doesn’t even have to go through WWW), can you simply check in Update for “isPlaying” do you get false when it’s over? :slight_smile:

I dont think isPlaying is reliable.
In my previous testing I’m pretty sure it isn’t.

The difficulty I have is its very difficult to tell in debug mode, because by the time it steps through the code it has finished.
I think it appears to work the first time. But not subsequent times.

What I actually see if debugging is it plays the first sound.
It then seems to go through properly and should play the 2nd one but doesn’t.
I I think click stop in the unity player, I actually get the start or the sound.

I’ve taken out the bit I added where I was trying to get the length of the file, now I’m back as I was relying on isPlaying - I think that is simpler.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Text;

using System.Text.RegularExpressions;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using System;

using UnityEngine.Networking;
public class TestSound : MonoBehaviour {
    public GameObject textBox;
    public AudioSource g03AudioSource;
    bool playingSoundFile = false;
    bool loadingAudioClip = false;
    bool needToLoadAudioclip = true;
    bool needToCheckForAudioclip = false;
    int clipCount = 2;
    int clipIndex = 0;
    float progress;
    UnityWebRequest www;
    // Use this for initialization
    void Start () {
        textBox.GetComponent<Text>().text = Application.persistentDataPath;

    }

    // Update is called once per frame
    void Update () {
        ReplayAllSounds ();
        checkIfSoundFileLoaded ();
    }
    // Replay All SOunds
    public void ReplayAllSounds(){
        if (clipIndex <= clipCount && playingSoundFile == false && loadingAudioClip == false && needToLoadAudioclip == true){
            textBox.GetComponent<Text> ().text = Application.persistentDataPath + "/test" + clipIndex + ".wav";
            loadingAudioClip = true;
            needToCheckForAudioclip = true;
            playingSoundFile = false;
            www = UnityWebRequestMultimedia.GetAudioClip (Application.persistentDataPath + "/test" + clipIndex + ".wav", AudioType.WAV);
            www.SendWebRequest ();

        } 

    }

    void checkIfSoundFileLoaded(){
        if (needToCheckForAudioclip == true) {
            if (www.isDone) { // If loaded
                loadingAudioClip = false;
                textBox.GetComponent<Text> ().text = "ISLOADED " + clipIndex;
                if (!g03AudioSource.isPlaying) { // If not playing
                    // First time not playing - startplaying
                    if (playingSoundFile == false) {
                        playingSoundFile = true;
                        textBox.GetComponent<Text> ().text = "ISPLAYING " + clipIndex;
                        playingSoundFile = true; //set flag to say playing
                        AudioClip audioClip = DownloadHandlerAudioClip.GetContent (www);
                        g03AudioSource.clip = audioClip;
                        g03AudioSource.Play (); // and play
                    } else {
                        {
                            g03AudioSource.Stop ();
                            www.Abort ();
                            www.Dispose ();
                            playingSoundFile = false;
                            loadingAudioClip = false;
                            needToCheckForAudioclip = false;
                            needToLoadAudioclip = true;
                            clipIndex++; // move on to next one
                        }
                    }
                }
            }
            }
        }

There’s a mild confusion where you wrote you don’t think isPlaying is reliable but then you are back to using it :slight_smile:

What I was trying to get at/learn is if you can rely on isPlaying, I would set your code up like this:

  1. begin playing file (request) …
  2. call coroutine to load next audio clip
  3. when loaded, begin playing
  4. check in update (or coroutine) if it’s playing
  5. when done, increment index and goto: 1

and remove your other calls in update

Thanks. I’m using it as I dont know how else to reliably do it unfortunately.
I was hoping somebody knows or has done this.
If you read my other thread (its a long one) I’ve tried yield, I’ve tried coroutines, I just couldn’t get it working.
Then every time someone suggested another way I just went down another dead end.

Hence starting afresh to see if anyone has done this before.

I also found the following, but couldn’t get that to work either!

Part of the issue of course is my limited c# and Unity skills. I’m been putting my app together using other’s code where I’ve got stuck.

This time I have got stuck and nobody seems to have done anything similar, even though in theory it doesn’t sound like a particularly complicated way to do it.

One other option is to forget about the playing of the clips, and instead combine them into a single large clip that I can just play. I may start another thread on that, as at least it would get around the isPlaying issue.

Ya, if they always play together, making one clip sounds reasonable.
If you want to share a few small music clips in a zip file, some online storage you have and paste a link here… I’d be happy to try to get it working when I have a free few mins , just to see if I can - for fun :slight_smile:

I’d be absolutely delighted if you can get that working! It will just be these files in this order, doesn’t need to be any more flexible than being able to write them out to one big file.

The difficulty seems to be they need to be loaded with WWW rather than just attached to the project.

I’ve PM’d you with a link to some sample files.

Not sure if it helps, but this was the next dead end I was going to try driving down:

Well, no promises we’ll see what happens lol.

Thank You. Much appreciated.

Okay got it working now.

int clipIndex = 0;
    AudioSource audioSource;
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        print("App : " + Application.persistentDataPath);
        StartCoroutine(PlayClips());
    }
    IEnumerator PlayClips()
    {
        for(int i = 1; i < 4; ++i)
        {
            clipIndex = i;
            print("PlayClips loop : index = " + i);
            yield return StartCoroutine(GetNextClip());
            print("PlayClips loop : after coroutine.");
        }
    }
    IEnumerator GetNextClip()
    {
        string clippath = Path.Combine("file://" + Application.persistentDataPath , "test" + clipIndex + ".wav");
        print("clip path: " + clippath);
        AudioClip myClip = null;
        using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(clippath, AudioType.WAV))
        {
            yield return www.SendWebRequest();

            if (www.isNetworkError)
            {
                Debug.Log(www.error);
            }
            else
            {
                myClip = DownloadHandlerAudioClip.GetContent(www);
            }
        }
        if (myClip != null)
        {
            print("clip length: " + myClip.length);
        }
        audioSource.clip = myClip;
        audioSource.PlayOneShot(myClip);
        yield return new WaitForSeconds(.1f);
        print("Begin play.");
        while (audioSource.isPlaying) yield return null;
        print("Play finished.");
    }

Surely I was slightly lazy at removing a few print statements and one yield (0.1f) that isn’t needed.
For like 20 mins I couldn’t even play the file, until I added “file://” sigh. lol that slowed me down.

I also didn’t retry “Play” instead of OneShot… as I changed that when nothing was working, early on.

Anyways… i’ll pass the trials onto you =)

Wow. You’re a genius. Thank you very much. That works perfectly.

However, I’ve now discovered one more HUGE problem:(

Some of these clips are microphone recordings.
I’m grabbing them with the code here, which I converted to c#

(post #9)

I’m hard coding tmerec to 20, as I dont know in advance how long the recording will be.
Which means my short recording is actually 20 seconds long. I hadn’t even realised up until now :face_with_spiral_eyes:
So it waits upto 20 seconds before playing the next one.

So it looks like I need to revisit this recording code. Looks lile there are functions to trim Silence, though I dont think they ever get called, and I’m really not sure what they even do. Maybe I need to call them when I hit my stop recording button. Unfortunately, it wasn’t totally clear to me what it was doing, it just ‘worked’

Once again its been a long day so I’ll have to revist tomorrow.

Many thanks for your help on this, the bit you have done works prefectly. On to the next problem!
EDIT: it looks to be further discussed here.

Ya, I would suggest that you either try to end the recording as soon as possible. If not, and whatever seems complicated or not working, find a useful audio editing program. you can probably cut it there :wink:
Luckily the ones you sent me didn’t have that lol … at least not that I noticed.

Oh, and you’re welcome :slight_smile: Take it easy.

Looking into the code a bit more, it seems the ultimate issue is the Microphone.Start functions requires a clip duration.
Null and 0 dont work.

But there does look to be a workaround here:

As per my earlier comment, its too late to start on this tonight, but hopefully it is just a case of slotting this in.

Thanks once again for your help earlier. Much appreciated.

For info, I managed to get your code fully integrated into my app, and also fixed the clip length using bits of the code I linked to above.
Many thanks again for your help.

Glad you got it working :slight_smile: