Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Using scripts to select a random section of a song

Discussion in 'Scripting' started by R850Mango, Mar 23, 2023.

  1. R850Mango

    R850Mango

    Joined:
    Apr 6, 2022
    Posts:
    3
    Good day all! I'm making a small game for my wife for our anniversary. She loves music quiz games because she can usually guess the song, artist and album after hearing like one or two seconds of any given song. Usually we watch youtube videos where they do the quiz in that format, but we've pretty much exhausted that supply, and the existing quiz apps aren't quite what she wants, so I decided to make something for her. The problem I'm running into (aside from general uselessness when coding) is that I can't find any help in Unity's official documentation for what I'm trying to do, which is why I came here.

    What I am trying to do is, using a script, select a random song from a folder -> select a random interval in that song -> play it -> wait 10 seconds -> display the file name and then move on to the next song. I'm struggling with the bit where the game selects a random interval in the song and plays it.

    Any help at all would be greatly appreciated!
     
  2. arkano22

    arkano22

    Joined:
    Sep 20, 2012
    Posts:
    1,660
  3. Magiichan

    Magiichan

    Joined:
    Jan 5, 2014
    Posts:
    403
    A coroutine would be appropriate to stop the song after 10 seconds.
    Here's some code i wrote up in notepad. Could have some syntax errors.
    Attach the script to a gameObject & assign the audioSource component in unity inspector panel.
    Also assign the songs to the script.

    When you start the game it'll start the PlayNextSong coroutine.
    1. selects a random clip.
    2. sets random starting time.
    3. plays audio.
    4. waits 10 seconds.
    5. stops audio.

    In order to play the next song, run StartCoroutine(PlayNextSong()); again.

    Code (CSharp):
    1.  
    2. public class Example: MonoBehaviour {
    3.  
    4.     public AudioSource source;
    5.     public List<AudioClip> songs;
    6.  
    7.     void Start() {
    8.         StartCoroutine(PlayNextSong());
    9.     }
    10.  
    11.     IEnumerator PlayNextSong() {
    12.         // Select random audio clip (probably better to have a psuedo-random approach)
    13.         source.clip = Random.Range(0, songs.Length);
    14.         // Set starting time
    15.         source.time = source.clip.length * Random.value;
    16.         // TODO: Make sure that the audioClip has 10 seconds to play by doing something like:
    17.         // source.time = Mathf.Clamp(source.clip.length * Random.value, 0, source.clip.length - 10);
    18.  
    19.         // Play audio
    20.         source.Play();
    21.         // Wait 10 seconds
    22.         yield return new WaitForSeconds(10);
    23.         // Stop clip
    24.         source.Stop();
    25.     }
    26. }
    27.  
    https://docs.unity3d.com/ScriptReference/AudioSource.Stop.html
    https://docs.unity3d.com/ScriptReference/WaitForSeconds.html
     
  4. R850Mango

    R850Mango

    Joined:
    Apr 6, 2022
    Posts:
    3
    Ok, so this is what I've hacked together

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5.  
    6. public class PlayButtonScript : MonoBehaviour
    7. {
    8.     public AudioSource audioSource;
    9.     public AudioClip[] audioArray;
    10.     public AudioClip loadedSong;
    11.     public float randomNumber;
    12.     public float offSetNo = 1.5f;
    13.     public float endNumber;
    14.  
    15.     void Start()
    16.     {
    17.         Invoke("SongArray", 0.1f);
    18.         InvokeRepeating("SelectSong", 0.5f, 16.1f);
    19.         InvokeRepeating("RandomSegment", 1.0f, 16.2f);
    20.         InvokeRepeating("PlayAudio", 1.5f, 16.5f);
    21.         InvokeRepeating("EndAudio", 3.0f, 18.0f);
    22.         InvokeRepeating("DisplayName", 11.0f, 26.0f);
    23.         InvokeRepeating("NextSong", 15.0f, 30.0f);
    24.     }
    25.  
    26.     void SongArray()
    27.     {
    28.         //Unsure how to get this to point to specific folder
    29.         audioArray[] = DirectoryInfo.GetFile("*.mp3");
    30.     }
    31.  
    32.     void SelectSong()
    33.     {
    34.         AudioClip loadedSong = audioArray[Random.Range(0, audioArray.Length)];
    35.     }
    36.  
    37.     void RandomSegment()
    38.     {
    39.         float randomNumber = Random.Range(0, loadedSong.length);
    40.     }
    41.  
    42.     void PlayAudio()
    43.     {
    44.         loadedSong.time = randomNumber;
    45.         AudioSource.PlayOneShot(loadedSong);
    46.     }
    47.  
    48.     void EndAudio()
    49.     {
    50.         AudioSource.Pause();
    51.     }
    52.  
    53.     void DisplayName()
    54.     {
    55.         //not sure what to do here
    56.     }
    57.  
    58.     void NextSong()
    59.     {
    60.         //again, unsure
    61.     }
    62.  
    63. }
    It, uh, doesn't work, but am I more or less on the right track?
     
    Magiichan likes this.
  5. Magiichan

    Magiichan

    Joined:
    Jan 5, 2014
    Posts:
    403
    upload_2023-3-23_12-14-7.png

    Since you've already defined the variables in the top of the class, you absolute don't have to redefine them.


    upload_2023-3-23_12-14-42.png
    This you are almost doing correctly, you're setting the value of the audioArray, but it should be
    Code (CSharp):
    1.  
    2. audioArray =DirectoryInfo.GetFile("*.mp3");
    3.  
    upload_2023-3-23_12-16-2.png
    By specifying the type as I've underlined with red, you're defining a new variable, instead of assigning a new value to the existing randomNumber.
    Remove the red underlined types in these two functions in order to use the correct variables.

    I'd recommend the script I've wrote for you, because there are just too many faults in this one.
    For example that the InvokeRepeating will de-synchronize.

    It's very hard to explain this all because it seems that you don't have the basics of programming down.
    Anyhow it's very cute that you want to do this for your wife! :)
     
  6. R850Mango

    R850Mango

    Joined:
    Apr 6, 2022
    Posts:
    3
    Aw thanks ^^;
    Yeah I'll just use your code I think, but it was still fun to give it an honest go!
    Thank you both for your help!
     
    Magiichan and Kurt-Dekker like this.
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,711
    Mango, this is a great attitude ^ ^ ^... and also a great way to expand your brain in new ways. This is how I started out many moons ago... I was absolutely drawn to trying everything, and I constantly did stuff wrong, but I kept after it, learned, refined, combined, etc.

    Let me offer you this insight on how to debug what you have, to understand the things you cobble together, how to debug your code... it's a lot easier than you think. Check it:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Magiichan likes this.