0

For the sake of making a (shuffled) playlist, I've made a separate thread in which I load and play each song in the playlist. The background stuff (wav files, file paths, playlists and shuffling) all work without a hitch.

The issue is that I have 2 windows, each of which can close and open the other. Each window has a different playlist, and when I switch to the other window, I want my static SoundPlayer to stop playing, then start playing the new playlist.

This currently isn't working: currently, the application waits until the current track is finished before displaying the next window and starting the other playlist. Yes, the entire application waits on this.

I'm new to thread coding, so I'm not really sure what to do. The two methods of stopping this I've tried so far have been SoundPlayer.Stop() and Thread.Abort(). Neither changes the situation at all.

In each window:

Thread playlistThread;
public Window()
{
    InitializeComponent();
    MusicPlayer.music.Stop();
    playlistThread = new Thread(() => MusicPlayer.PlayPlaylist(MusicPlayer.ShufflePlaylist(MusicPlayer.PlaylistFromType("[insert track type]"), random)));
    playlistThread.Start();

PlayPlaylist which I will show next takes a List of strings, so don't worry about the Thread line, it's just a few sections put into one. The properties after that simply generate that list, and again, that all works, but I can show it if anyone thinks it's necessary. Here is the PlayPlaylist method:

public static void PlayPlaylist(List<string> tracks)
{
    for (int i = 0; i < tracks.Count; i++)
    {
        music.SoundLocation = tracks[i];
        music.PlaySync();
    }
}
  • just fyi this won't work on many windows 10 computers because soundplayer requires media player to be installed. – John Lord Oct 23 '19 at 05:06
  • I'm fairly sure it doesn't - MediaPlayer is another class that uses WMP, but I don't think SoundPlayer does – Jack Rodden Oct 24 '19 at 08:00
  • I'm fairly sure it does since i have windows 10 R installed and i can't use that class. I can't even use the Mono version of it. – John Lord Oct 24 '19 at 16:48
  • If you are using an older version of VS, you may have to manually add the dll: it's apparently from PresentationCore.dll, but there's nothing indicating it's only present on some Windows machines. All Windows PCs use .Net, so it shouldn't be an issue. – Jack Rodden Oct 24 '19 at 18:08
  • I use 2017 enterprise and 2019 community. Yes all pcs use net, but some systems are sold without media capability at all built-in. I've had even media players that are supposedly 3rd party not run without the media extension pack installed, and i can assure you that that library is a wrapper for the media player dlls. I had to rewrite some of my own software to not use it. My point is this: You can't rely on the built-in media capabilities to be on a system anymore thanks to that EU ruling. https://support.microsoft.com/en-us/help/4475817/media-feature-pack-for-windows-10-n-may-2019 – John Lord Oct 24 '19 at 20:28
  • as a correction (since it's too old to edit) i mistakenly said i have windows 10 R. I have the UK windows 10 N. – John Lord Oct 24 '19 at 20:29
  • If their computer doesn't have media capabilities I think they have bigger issues, to be frank – Jack Rodden Oct 26 '19 at 04:07
  • i've got media capabilities. I edit videos on it in Vegas studio. My point is you can not expect that particular library to be on a computer any more thanks to a EU ruling that claimed monopoly status on the windows media player. Microsoft was forced to sell windows 10 optionally without the built-in media apps or libraries and i run that version on my main development rig. I've only ever had one commercial app fail because of it-a vr movie player that depended on the api. – John Lord Oct 28 '19 at 18:10
  • Well, while it's useful to know, it won't affect my program's users. If I were to ship to the EU I'd make sure to package WMP with the program. – Jack Rodden Oct 29 '19 at 14:06
  • I don't live in the EU. I live in indiana. Many people in the US are getting that version from colleges and it's where i got it. There IS an add-on pack that restores it but annoyingly they are specific to whatever version you've updated to. – John Lord Oct 29 '19 at 15:51

1 Answers1

0

Here's the answer I worked out:

public static void PlayTrack(List<string> tracks, int i)
{
    while (true)
    {
        if (i == tracks.Count)
        {
            tracks = MusicPlayer.ShufflePlaylist(tracks, MusicPlayer.random);
            i = 0;
        }
        music.SoundLocation = tracks[i];
        int l = SoundInfo.GetSoundLength(tracks[i]);
        music.Play();
        while (l > 0)
        {
            Thread.Sleep(1000);
            l -= 1000;
        }
        i++;
    }
}

The SoundInfo class with its GetSoundLength method I found here. The reason this method works while others do not is because of how Play() and PlaySync() work. PlaySync() plays the entire .wav file in the current thread, with nothing else running until it finishes. Thus, even SoundPlayer.Stop() and Thread.Abort() do not work, as they insert a new line after the current one.

By running this method in a new thread, you avoid PlaySync() giving you that issue. However, it will still be impossible to stop the track ahead of time using PlaySync(). This is why you use Play() instead.

Therein lies a second issue, however: Play() plays the track in its own thread, meaning the rest of the code will continue. This is a big risk if you're wanting to do anything only after the current track finishes.

The answer is to calculate the length of the track you're going to play. Then simply create a while loop, running until l (given by GetSoundLength()) reaches 0. In each pass through the loop the thread (separate from your window's main thread) sleeps for 1 second. This is fine on the CPU and means that every second extra code, such as SoundPlayer.Stop(), can be injected into the thread.