/// <summary> /// Sorts the play queue into a random order. /// </summary> public void ShufflePlayQueue() { bool wasPlayingBefore = false; if (ToccataModel.MediaPlayerIsPlaying()) { wasPlayingBefore = true; } this.Stop(); // Construct a list of all the items in the play queue (we will pull random items off it, in the code below). List <PlayableItem> playableItemList = new List <PlayableItem>((IEnumerable <PlayableItem>) this.PlayQueue); this.PlayQueue.Clear(); Random random = new Random(); while ((uint)playableItemList.Count > 0U) { int index = 0; if (playableItemList.Count > 1) { index = random.Next(0, playableItemList.Count); // pick a random index in the list } PlayableItem playableItem = playableItemList[index]; // add the random item to the play queue, and remove it from the list. playableItemList.RemoveAt(index); this.PlayQueue.Add(playableItem); } if (wasPlayingBefore) { this.StartPlayingIfAppropriate(); } }
/// <summary> /// Stop playing the current track and move it to the history, then start playing the track that is now the top of the play queue. This is the right /// metyhod to call when the 'Next' button is tapped. /// </summary> public void Next() { if (this.PlayQueue.Count <= 1) // if there is no queued track, do nothing. If there is only one queued track, then there is no next track, so do nothing. { return; } // This is a bit nasty and hacky - if the next button is pressed repeatedly in quick succession, the player // may be transiently paused when the button is pressed for the second, third, ... etc time, as a result of // an earlier press. So our logic for checking whether the player is playing now, and should therefore be // restarted after we have skipped forward a track, needs to be careful to ignore those transient state changes. // Hence this code, which says we will examine the player state only if the button hasn't already been pressed // in the recent past. if (_dtNextPressed.AddMilliseconds(500) < DateTime.Now) { _wasPlayingBeforeNextPressed = ToccataModel.MediaPlayerIsPlaying(); } _dtNextPressed = DateTime.Now; this.Stop(); this.history.Insert(0, this.PlayQueue[0]); // Take the currently playing track (the one at the top of the queue), add it to the history this.PlayQueue.RemoveAt(0); // and remove it from the play queue. if (_wasPlayingBeforeNextPressed) { this.StartPlayingIfAppropriate(); } }
/// <summary> /// Remove an item from the play queue. If it's the top item of the queue, and currently playing, then stop playing it, and /// start playing the next on the queue. /// </summary> /// <param name="i">item to remove</param> public void DeleteFromQueue(PlayableItem i) { if (this.PlayQueue.Count <= 0) { return; } bool wasPlayingBefore = false; if (ToccataModel.MediaPlayerIsPlaying()) { wasPlayingBefore = true; } if (this.PlayQueue[0] == i) // if we're removing the top item of the queue (i.e. the current track) { this.Stop(); // then hard-stop playback } this.PlayQueue.Remove(i); if (wasPlayingBefore) { this.StartPlayingIfAppropriate(); } }
/// <summary> /// Stops playing the current track (if it's playing) and goes back to the start of the previous track we were playing. /// </summary> public void Back() { if (this.history.Count <= 0) { return; } // This is a bit nasty and hacky - if the back button is pressed repeatedly in quick succession, the player // may be transiently paused when the button is pressed for the second, third, ... etc time, as a result of // an earlier press. So our logic for checking whether the player is playing now, and should therefore be // restarted after we have skipped back a track, needs to be careful to ignore those transient state changes. // Hence this code, which says we will examine the player state only if the button hasn't already been pressed // in the recent past. if (_dtBackPressed.AddMilliseconds(500) < DateTime.Now) { _wasPlayingBeforeBackPressed = ToccataModel.MediaPlayerIsPlaying(); } _dtBackPressed = DateTime.Now; this.Stop(); this.PlayQueue.Insert(0, this.history[0]); // Put the top track from ths history list onto the top of the play queue, this.history.RemoveAt(0); // and remove it from the history list if (_wasPlayingBeforeBackPressed) { this.StartPlayingIfAppropriate(); } }
private static bool _SliderIsBeingManipulated = false; // set to true while the user is manually manipulating the slider private void slPosition_SliderManipulationStarted(object sender, EventArgs e) { MainPage._SliderIsBeingManipulated = true; if (ToccataModel.MediaPlayerIsPlaying()) MainPage._WasPlayingWhenManipulationStarted = true; MainViewModel.Instance.Pause(); }
/// <summary> /// Start playing, from the start of the track, if: (1) there is a queued track to play and (2) the player is in the hard-stopped state at the moment /// </summary> public void StartPlayingIfAppropriate() { if (this.PlayQueue.Count == 0 || !ToccataModel.MediaPlayerHasNoSource()) { return; } ToccataModel.Play(this.PlayQueue[0].storage); // start playing the track that is at the top of the queue. }
/// <summary> /// Starts or restarts playback. /// </summary> public void Play() { if (ToccataModel.MediaPlayerHasNoSource()) // if the player has been hard-stopeed, then ... { if (this.PlayQueue.Count <= 0) { return; } ToccataModel.Play(this.PlayQueue[0].storage); // ... play the top track on the queue } else { ToccataModel.Play(); // ... else play whatever is currently assigned as the player's source. } }
/// <summary> /// Clears the existing lists of albums and tracks, and then loads a new list of albums for a given artist. /// </summary> /// <param name="f">the folder whose name is the artist name</param> public async void OpenArtistFolder(FolderEntry f) { this.Albums.Clear(); this.Tracks.Clear(); if (string.IsNullOrEmpty(f.DisplayName)) { this.AlbumsFolderLabel = ""; } else { this.AlbumsFolderLabel = "(in " + f.DisplayName + ")"; } this.TracksFolderLabel = ""; await ToccataModel.PopulateFolderItems(this.Albums, f.storage as StorageFolder); }
/// <summary> /// Clears the existing lists of tracks, and then loads a new list of tracks for a given album. /// </summary> /// <param name="f">the folder whose name is the album name</param> public async void OpenAlbumFolder(FolderEntry f) { this.Tracks.Clear(); if (string.IsNullOrEmpty(f.DisplayName)) { this.TracksFolderLabel = ""; } else { this.TracksFolderLabel = "(in " + f.DisplayName + ")"; } await ToccataModel.PopulateFolderItems(this.Tracks, f.storage as StorageFolder); if (this.PlayQueue.Count == 0) // if there are no tracks already queued to play, { this.AddTracks(); // auto-add the ones we just found in this folderto the play queue } }
/// <summary> /// Call this method before trying to play music. /// It sets up and reads the root folder (where the list of artists is). This is initialised to the user's top-level Music /// folder, but can be changed. Also it sets up the media player. /// </summary> public void Initialise() { this.RootFolder = KnownFolders.MusicLibrary; // a side-effect in the accessor will cause the folder to be read in to the Artists list. ToccataModel.SetUpMediaPlayer(); }
//private DispatcherTimer _dtimer = null; private async void ThrottledPlaybackStateChanged(MediaPlayer player) { if (_playbackStateChangePending) { // A change has already been noted, and the 'state changed' handler will get called anyway some time within the next 100ms return; } else { _playbackStateChangePending = true; await Task.Delay(100); // allow 100ms for subsequent state changes to come in _playbackStateChangePending = false; // // Now adjust the appearance of the Pause/Play button as needed, and kick off playback of the next track in the queue, if there is one. // if (player.PlaybackSession == null) // error - never started { } else if (player.PlaybackSession.PlaybackState == MediaPlaybackState.Paused) { bool trackFinished = false; //at the end of a track? if (player.PlaybackSession.Position != TimeSpan.Zero && player.PlaybackSession.Position.Add(TimeSpan.FromSeconds(1)) >= player.PlaybackSession.NaturalDuration) { // Position is not at the start of the media, and is equal/near to the duration of the player's media, // This means we are at the end of a track trackFinished = true; } MainPage.SetPlayButtonAppearance(false); // Set the Play button to display a "play" label, and do 'play' when tapped. if (trackFinished) // paused, and at the end of a track { MainPage.SetNowPlaying(""); // "***FINISHED: " + player.PlaybackSession.PlaybackState.ToString() + " " + player.PlaybackSession.Position.TotalSeconds.ToString() + "/" + player.PlaybackSession.NaturalDuration.TotalSeconds.ToString()); // set the text label at the bottom of the slider to blank. if (PlayQueue.Count > 0) // (this is just defensive coding, it should always be true) { PlayQueue.RemoveAt(0); // We've finished this track, so remove it from the top of the play queue. } if (PlayQueue.Count > 0) // if there is now a track at the top of the queue ... { ToccataModel.Play(this.PlayQueue[0].storage); // ... start playing it. } else { ToccataModel.Stop(); // ... otherwise, we should hard-stop the player, leaving it ready to play something, when something is queued up. } } else // paused but not finished the track - e.g. because the user tapped the Pause button. { // MainPage.SetNowPlaying("***PAUSED: " + player.PlaybackSession.PlaybackState.ToString()+" "+ player.PlaybackSession.Position.TotalSeconds.ToString()+"/"+ player.PlaybackSession.NaturalDuration.TotalSeconds.ToString()); } } else // playing, buffering, opening, none, or whatever { if (player.PlaybackSession.PlaybackState == MediaPlaybackState.Playing) { MainPage.SetPlayButtonAppearance(true); // Set the Play button to display a "pause" label, and do 'pause' when tapped. } else // could be 'buffering', 'opening' or 'none' - anyhow, it's a state in which the media is not (yet) playing. { MainPage.SetPlayButtonAppearance(false); // Set the Play button to display a "play" label, and do 'play' when tapped. } if (PlayQueue.Count > 0) // (this is just defensive coding, it should always be true) { MainPage.SetNowPlaying(PlayQueue[0].DisplayName + " (" + PlayQueue[0].storage.Path + ")"); } } } }
/// <summary> /// Set the playback position. /// </summary> /// <param name="t">playback position to set</param> public void SetPlayerPosition(TimeSpan t) { ToccataModel.SetPlayerPosition(t); }
/// <summary> /// Stop playback and empty the play queue. /// </summary> public void ClearQueue() { ToccataModel.Stop(); this.PlayQueue.Clear(); }
/// <summary> /// Pauses playback (which is to say, stops it, but does not hard-stop it). /// </summary> public void Pause() { ToccataModel.Pause(); }
/// <summary> /// Stops the media player (it puts it into the 'hard-stopped' state). /// </summary> public void Stop() { ToccataModel.Stop(); }