Question Get current item in Randomized List

60int

New member
Joined
Jun 24, 2022
Messages
2
Location
Budapest
Programming Experience
1-3
Hello

I have made a simple music player that plays a randomized list of songs and when a song stops, it starts playing the next song:

MusicPlayer:
public class PlayrList
    {
        private Queue<string> playlist;
        private IWavePlayer player;
        private WaveStream fileWaveStream;
        public PlayrList(List<string> startingPlaylist)
        {
            playlist = new Queue<string>(startingPlaylist);
        }
        public void PlaySong()
        {
            if (playlist.Count < 1)
            {
                return;
            }

            if (player != null && player.PlaybackState != PlaybackState.Stopped)
            {
                player.Stop();
            }
            if (fileWaveStream != null)
            {
                fileWaveStream.Dispose();
            }
            if (player != null)
            {
                player.Dispose();
                player = null;
            }

            player = new WaveOutEvent();
            fileWaveStream = new AudioFileReader(playlist.Dequeue());
            player.Init(fileWaveStream);
            player.PlaybackStopped += (sender, evn) => { PlaySong(); };
            player.Play();
        }
        public void PauseSong()
        {
            if (player != null)
            {
                if (player.PlaybackState == PlaybackState.Playing)
                {
                    player.Pause();
                }
                else if (player.PlaybackState == PlaybackState.Paused)
                {
                    player.Play();
                }
            }
        }
        public void NextSong()
        {
            try
            {
                player.Dispose();
                player = null;
                fileWaveStream.Dispose();
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Can't play Next Song", ex);
            }
        }
    }

I would like to display the current songs name on a label and when it switches to another song it displays the new song, but I'm not sure how to go about it. I was thinking maybe giving a SongLength property to every song and then using Timer.Tick somehow. I am able to display the list of songs in a listbox.


MainForm:
static readonly List<Song> Songs = new List<Song>();

        public static readonly Random rnd1 = new Random();

        public List<string> Playlist { get; set; }
        
        public PlayrList Player { get; set; }

        public Form1()
        {
            InitializeComponent();

            Resources.songs.Split(new string[] { Environment.NewLine }, StringSplitOptions.None).ToList().ForEach(a => Songs.Add(new Song(a)));

            Playlist = new List<string>()
            {
                Songs[0].SongFilePath.ToString(),
                Songs[1].SongFilePath.ToString(),
                Songs[2].SongFilePath.ToString(),
                Songs[3].SongFilePath.ToString(),
                Songs[4].SongFilePath.ToString(),
                Songs[5].SongFilePath.ToString()
            }.OrderBy(a => rnd1.Next()).ToList();

            Player = new PlayrList(Playlist);
        }
        private void Button1_Click(object sender, EventArgs e)
        {
            Player.PlaySong();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            Player.NextSong();
        }

Any help would be appreciated!
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
5,469
Location
Chesapeake, VA
Programming Experience
10+
Each time PlaySong() is called, you should also fire off a event that contains information about the song being played. In your UI, listen for that event and update the labels in your UI.
 

cjard

Member
Joined
Jan 25, 2012
Messages
17
Programming Experience
10+
Each time PlaySong() is called, you should also fire off a event that contains information about the song being played. In your UI, listen for that event and update the labels in your UI.

And that could look like:

C#:
public class PlayrList
{
    //create an event
    public event EventHandler<string> NowPlaying;

    ...

        //cache the filename being played
        var f = playlist.Dequeue();

        fileWaveStream = new AudioFileReader(f);
        player.Init(fileWaveStream);
        player.PlaybackStopped += (sender, evn) => { PlaySong(); };
        player.Play();

        //raise the event
        var e = NowPlaying;
        e?.Invoke(this, f);
    }




//in main form constructor

            Player = new PlayrList(Playlist);

            //attach event handler that sets the text of the label called _nowPlayingLabel
            Player.NowPlaying += (s,e) => _nowPlayingLabel.Text = e;

        }


Do please rename your controls after you drop them on a form. Noone (not even you, in 3 months, I promise) will want to read code that is stuffed full of Button27, TextBox56 - naming variables a mix of random characters irrelevant to their function is called obfuscation; something designed to make code hard to read to prevent it being maintained or copied. Writing good clear code should always be the goal for you and for any other developers you work with
 

cjard

Member
Joined
Jan 25, 2012
Messages
17
Programming Experience
10+
By the way, assuming the list in resources is just the filepaths, the rest of your code in your constructor could look like:

C#:
            var songs = Resources.songs.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);

            Songs.AddRange(songs.Select(s=>new Song(s));

            Playlist = songs.OrderBy(s => rnd1.Next()).ToList();
 
Top Bottom