1

I have an audio clip and a slider. The slider is acting as a progress bar (Timeline) for the audio clip. I can pause and play the audio also I can skip the track as well. Everything is working fine. The problem is slider isn't moving smoothly it's kinda jittery. Please edit it if somebody can. Thanks in advance.

Here is the code:

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

public class MusicPlayer : MonoBehaviour
{
    AudioSource audioSource;
    Slider slider;
    public AudioClip track;

    // Start is called before the first frame update
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        slider = GetComponent<Slider>();

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

        slider.minValue = 0;
        slider.maxValue = track.length;
    }

    // Update is called once per frame
    void Update()
    {
        slider.value = audioSource.time;
        
    } 

    public void MovePoition()
    {
        audioSource.time = slider.value;
    }

    public void play()
    {
        audioSource.Play();
    }

    public void pause()
    {
        audioSource.Pause();
    }

}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
Mirza Zeeshan
  • 99
  • 4
  • 12

1 Answers1

0

On Update, ensure smoothness by using Time.deltaTime to update the slider's value if it is playing. Otherwise, and also in play and pause, re-sync the position with the playtime.

However, you need to avoid the callback when setting the value. Create an empty event at Start and assign it to the slider when updating the value.

Finally, add a flag to keep track of if the track should be playing. This prevents the source from stopping when the end of the clip is played then the slider is dragged.

After setting the source time in MovePoition, depending on the compression of the clip, it might not be able to set to the exact value the slider has. So, you should re-update the slider value with the time that the audio source decides to use.

Altogether:

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

public class MusicPlayer : MonoBehaviour
{
    AudioSource audioSource;
    Slider slider;
    Slider.SliderEvent emptyEvent;
    public AudioClip track;
    private bool isPaused;
    private bool needSync;

    // Start is called before the first frame update
    void Start()
    {
        audioSource = GetComponent<AudioSource>();
        slider = GetComponent<Slider>();

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

        slider.minValue = 0;
        slider.maxValue = track.length;

        emptyEvent = new Slider.SliderEvent();
    }

    void SetSliderWithoutCallback(float time) 
    {
        Slider.SliderEvent temp = slider.onValueChanged;
        slider.onValueChanged = emptyEvent;
        slider.value = time;
        slider.onValueChanged = temp;
    }

    // Update is called once per frame
    void Update()
    {
        if (audioSource.isPlaying) 
        {
            float newTime = Mathf.Min(slider.value + Time.deltaTime, slider.maxValue);
            SetSliderWithoutCallback(newTime);
        } 
        else if (!isPaused)
        {
            SetSliderWithoutCallback(slider.maxValue);
            isPaused = true;
        }
    } 

    public void MovePoition()
    {
        audioSource.time = slider.value;
        if (!isPaused) 
        {
            audioSource.Play();
            SetSliderWithoutCallback(audioSource.time);
        }
    }

    public void play()
    {
        audioSource.Play();
        isPaused = false;
        SetSliderWithoutCallback(audioSource.time);
    }

    public void pause()
    {
        isPaused = true;
        audioSource.Pause();
        SetSliderWithoutCallback(audioSource.time);
    }

}
Ruzihm
  • 19,749
  • 5
  • 36
  • 48
  • It is still jittery and moving fast now. Also the audio isn't clear now. – Mirza Zeeshan Sep 23 '20 at 16:55
  • @MirzaZeeshan I changed `Update`, `play`, and `pause`. See if that works for you. – Ruzihm Sep 23 '20 at 17:01
  • I am getting this error. Assets\Scripts\MusicPlayer.cs(31,20): error CS0122: 'Slider.Set(float, bool)' is inaccessible due to its protection level – Mirza Zeeshan Sep 23 '20 at 17:07
  • @MirzaZeeshan One more update. I tested this on my system and it seems to work perfectly fine. – Ruzihm Sep 23 '20 at 17:33
  • The Slider is moving smoothly, but when you play with the slider a few times I mean on runtime if you backward the music 2 or 3 times then it's not playing the audio clip completely it's missing the clip. – Mirza Zeeshan Sep 23 '20 at 18:29
  • @MirzaZeeshan It's missing the clip? Not sure what you mean by that. Maybe the audioclip hit its end and the source stopped playing because of that. I added a flag to change whether the source should be playing or not. – Ruzihm Sep 23 '20 at 18:48
  • Here is the link, https://youtu.be/Viar7t0wrfk I have made a video about the problem I am facing. After pausing and playing a few times you can see the audio clip isn't playing completely. Please have a look. Thanks in advance. – Mirza Zeeshan Sep 24 '20 at 06:56
  • @MirzaZeeshan So, depending on the compression of the clip, it might not allow you to set the source to be certain times, so it will be slightly different from the value of the slider. I added `SetSliderWithoutCallback` at the end of `SetPoition` (by the way, you might want to change it to be named `SetPosition`) to force the slider to be exactly where the time that the clip allows it to seek. – Ruzihm Sep 24 '20 at 14:34
  • Sorry mate I have tested it but the problem is still there. – Mirza Zeeshan Sep 24 '20 at 15:22
  • I still can't reproduce the problem on my end. What if you call `audioSource.Play();` at the start of `play` instead the end? – Ruzihm Sep 24 '20 at 15:46
  • If there is no problem on your side then could you please send me the package? It would be great. Here is my email: mirzazeeshan918@gmail.com – Mirza Zeeshan Sep 24 '20 at 16:08
  • @MirzaZeeshan I don't have the audio clip you're using so I have no idea if it will work for you. Did moving `audioSource.Play` at the beginning help? – Ruzihm Sep 24 '20 at 16:08
  • @MirzaZeeshan So when you say "the audio clip isnt playing completely" does that mean that the audio plays completely and it is only the slider that stops early? Or does that mean that the audio gets cut off? There was no audio in the video you posted so I can't tell. In the event it is just a visual concern, I made the slider move to the end when the audio source stops playing on its own. Let me know if that fixes your problem. – Ruzihm Sep 24 '20 at 16:44
  • I meant to say the audio gets cut off. I have tried the new script. It seems if I play and pause the audio with buttons it's working fine but if while playing I pause the audio and move the slider in the middle like from where I want to listen again, after finishing whenever I play the audio it starts from the middle. Like I need to drag the slider manually at the beginning. Everything else is working fine. – Mirza Zeeshan Sep 24 '20 at 17:05
  • I'm not sure what you mean. Are you saying you are pausing and resuming the audio without using `pause` and `play`? – Ruzihm Sep 24 '20 at 17:13