Issues with music player in Unity

Viewed 423

So I've been working on a music player in Unity. It gets the audioclips from an array within Unity, and a random number generator picks a clip between 0 and the size set in Unity. However, nothing stops it from picking the same number (and thus same song) twice in a row which is something I do not want. I've been trying a few things but ended up with a NullReferenceException. If you'd like to take a look I'd greatly appreciate it!

Code:

using System.Collections;
using UnityEngine;

public class MusicPlayer : MonoBehaviour
{
    #region Variables

    //Variables needed for this code
    public AudioClip[] clips;

    private AudioSource audioSource;

    string currentTitle = "";

    #endregion

    #region Start Void
    // Start is called before the first frame update
    void Start()
    {
        //Finds AudioSource in the unity editor and turns off the "loop" function.
        audioSource = FindObjectOfType<AudioSource>();
        audioSource.loop = false;
    }
    #endregion

    #region Private AudioClip
    //The code below will grab a random audio clip between 0 and the amount set in the Unity Editor.
    private AudioClip GetRandomClip()
    {
        return clips[Random.Range(0, clips.Length)];

    }
    #endregion

    #region Update Void
    // Update is called once per frame
    void Update()
    {


        if (audioSource.clip.name.Length >= 0)
        {
            currentTitle = audioSource.clip.name;
        }

        if (!audioSource.isPlaying)
        {
            var nextTitle = currentTitle;
            ulong index = 0;
            while (nextTitle == currentTitle)
            {
                index = (ulong) Random.Range(0, clips.Length);
                nextTitle = clips[index].name;
            }
            audioSource.Play(index);
        }


    }
    #endregion
}

Went back into my code to prepare it for future stuff as well like calling audio clips from multiple arrays and with the help of both Silleknarf and derHugo I got it worked out. Thank you all so much. Here is the code I ended up with:

/*
    AudioPlayer.cs
    RTS Game

    Created by Robin den Ambtman on 17-06-2019
    Copyright © Robinblitz. All rights reserved.
*/

using System.Collections;
using UnityEngine;
using System.Linq;

public class AudioPlayer : MonoBehaviour
{
    #region Variables

    //Variables needed for this code

    [Header("Sound arrays")]
    public AudioClip[] musicClips;
    [Space(10)]
    public AudioClip[] announcerClips;
    [Space(10)]
    public AudioClip[] TBDClips;

    [Header("Effect/Music sources")]
    public AudioSource effectAudioSource;
    public AudioSource musicAudioSource;

    #endregion

    #region Start Void
    // Start is called before the first frame update
    void Start()
    {
        //Finds AudioSource in the unity editor and turns off the "loop" function.
        musicAudioSource.loop = false;
        Random.InitState((int)System.DateTime.Now.Ticks);
    }
    #endregion

    #region Music RNG
    //The code below will grab a random audio clip between 0 and the amount of clips set in the Unity Editor.
    private AudioClip GetRandomMusicClip()
    {

        // This returns only those clips that are not the currenty played one
        var filteredClips = musicClips.Where(c => c != musicAudioSource.clip).ToArray();

        return filteredClips[Random.Range(0, filteredClips.Length)];
    }
    #endregion

    #region Update Void
    // Update is called once per frame
    void Update()
    {
        //If the audio source is playing it will grab the song that's picked out by GetRandomClip() and plays it.
        if (!musicAudioSource.isPlaying)
        {
            var newTitle = GetRandomMusicClip();
            musicAudioSource.clip = newTitle;
            musicAudioSource.Play();
        }

        //Piece of code as a test to play a specific audio clip on key press.
        if (Input.GetKeyDown(KeyCode.Space))
        {
            effectAudioSource.PlayOneShot(effectAudioSource.clip, 0.7f);
        }
    }
    #endregion
}

2 Answers

As already mentioed in the other answer the parameter of AudioSource.Play(ulong) is

delay
Deprecated.

Delay in number of samples, assuming a 44100Hz sample rate (meaning that Play(44100) will delay the playing by exactly 1 sec).

So what you want to do is

audioSource.clip = newClip;
audioSource.Play();

Then I would rather suggest using Linq Where and filter the unwanted (= currently playing) clip out beforehand without any while-loop like

using System.Linq;

...

private AudioClip GetRandomClip()
{
    // This returns only those clips that are not the currenty played one
    var filteredClips = clips.Where(c => c != audioSource.clip).ToArray();

    return filteredClips[Random.Range(0, filteredClips.Length)];
}

void Update()
{
    if (!audioSource.isPlaying)
    {
        var newTitle = GetRandomClip();
        audioSource.clip = newTitle;
        audioSource.Play();
    }
}

It looks like you don't set the clip for the audioSource using the audioSource.clip property. Perhaps it would be easier to change the string currentTitle variable to be a AudioClip currentClip and then just use the currentClip.title property when doing the equality comparisons. Then at the end just before you call the audioSource.Play() method you can set the clip as follows: audioSource.clip = nextTitle;.

Another thing to note is that the parameter to the audioSource.Play method is the delay rather than the index of the clip to play so you need to set the clip first and probably don't even need to pass a parameter to the audioSource.Play method.

Related