// MonoGame - Copyright (C) MonoGame Foundation, Inc
// This file is subject to the terms and conditions defined in
// file 'LICENSE.txt', which is part of this source code package.
using System;
namespace Microsoft.Xna.Framework.Media
{
///
/// Provides methods and properties to play, pause, resume, and stop songs.
/// MediaPlayer also exposes shuffle, repeat, volume, play position, and visualization capabilities.
///
public static partial class MediaPlayer
{
// Need to hold onto this to keep track of how many songs
// have played when in shuffle mode
private static int _numSongsInQueuePlayed = 0;
private static MediaState _state = MediaState.Stopped;
private static float _volume = 1.0f;
private static bool _isMuted;
private static bool _isRepeating;
private static bool _isShuffled;
private static readonly MediaQueue _queue = new MediaQueue();
///
/// Raised when the active song changes due to active playback or due to explicit calls to the
/// or methods.
///
public static event EventHandler ActiveSongChanged;
///
/// Raised when the media player play state changes.
///
public static event EventHandler MediaStateChanged;
static MediaPlayer()
{
PlatformInitialize();
}
#region Properties
///
/// Gets the media playback queue, .
///
public static MediaQueue Queue { get { return _queue; } }
///
/// Gets or set the muted setting for the media player.
///
public static bool IsMuted
{
get { return PlatformGetIsMuted(); }
set { PlatformSetIsMuted(value); }
}
///
/// Gets or sets the repeat setting for the media player.
///
///
/// When set to , the playback queue will begin
/// playing again after all songs in the queue have been played.
///
public static bool IsRepeating
{
get { return PlatformGetIsRepeating(); }
set { PlatformSetIsRepeating(value); }
}
///
/// Gets or sets the shuffle setting for the media player.
///
///
/// When set to , songs in the playback queue are
/// played in random order rather than from first to last.
///
public static bool IsShuffled
{
get { return PlatformGetIsShuffled(); }
set { PlatformSetIsShuffled(value); }
}
///
/// Gets or sets the visualization enabled setting for the media player.
///
///
/// Always returns
///
public static bool IsVisualizationEnabled { get { return false; } }
///
/// Gets the play position within the currently playing song.
///
public static TimeSpan PlayPosition
{
get { return PlatformGetPlayPosition(); }
#if (IOS && !TVOS) || ANDROID
set { PlatformSetPlayPosition(value); }
#endif
}
///
/// Gets the media playback state,
///
public static MediaState State
{
get { return PlatformGetState(); }
private set
{
if (_state != value)
{
_state = value;
EventHelpers.Raise(null, MediaStateChanged, EventArgs.Empty);
}
}
}
///
/// Determines whether the game has control of the background music.
///
///
/// If a gamer is currently playing their own music as the background to your game,
/// calls to , , ,
/// , , and
/// might have no effect, depending on the platform.
///
public static bool GameHasControl
{
get
{
return PlatformGetGameHasControl();
}
}
///
/// Gets or sets the media player volume
///
///
/// Media player volume, from 0.0f (silence) to 1.0f (full volume relative to the current device volume)
///
///
///
/// Volume adjustment is based on a decibel, not multiplicative, scale.
/// Setting to 0.0 subtracts 96 dB from the volume.
/// Setting to 1.0 subtracts 0 dB from the volume.
/// Values in between 0.0f and 1.0f subtract dB from the volume proportionally.
///
///
public static float Volume
{
get { return PlatformGetVolume(); }
set
{
var volume = MathHelper.Clamp(value, 0, 1);
PlatformSetVolume(volume);
}
}
#endregion
///
/// Pauses the currently playing song.
///
public static void Pause()
{
if (State != MediaState.Playing || _queue.ActiveSong == null)
return;
PlatformPause();
State = MediaState.Paused;
}
///
/// Play clears the current playback queue, and then queues up the specified song for playback.
/// Playback starts immediately at the beginning of the song.
///
public static void Play(Song song)
{
Play(song, null);
}
///
/// Play clears the current playback queue, and then queues up the specified song for playback.
/// Playback starts immediately at the given position of the song.
///
public static void Play(Song song, TimeSpan? startPosition)
{
if (song == null)
throw new ArgumentNullException("song", "This method does not accept null for this parameter.");
var previousSong = _queue.Count > 0 ? _queue[0] : null;
_queue.Clear();
_numSongsInQueuePlayed = 0;
_queue.Add(song);
_queue.ActiveSongIndex = 0;
PlaySong(song, startPosition);
if (previousSong != song)
EventHelpers.Raise(null, ActiveSongChanged, EventArgs.Empty);
}
///
/// Play clears the current playback queue, and then queues up the specified song collection for playback.
/// Playback starts immediately at the beginning of the song, specified by song collection index.
///
public static void Play(SongCollection collection, int index = 0)
{
if (collection == null)
throw new ArgumentNullException("collection", "This method does not accept null for this parameter.");
_queue.Clear();
_numSongsInQueuePlayed = 0;
foreach(var song in collection)
_queue.Add(song);
_queue.ActiveSongIndex = index;
PlaySong(_queue.ActiveSong, null);
}
private static void PlaySong(Song song, TimeSpan? startPosition)
{
if (song != null && song.IsDisposed)
throw new ObjectDisposedException("song");
PlatformPlaySong(song, startPosition);
State = MediaState.Playing;
}
internal static void OnSongFinishedPlaying(object sender, EventArgs args)
{
// TODO: Check args to see if song sucessfully played
_numSongsInQueuePlayed++;
if (_numSongsInQueuePlayed >= _queue.Count)
{
_numSongsInQueuePlayed = 0;
if (!IsRepeating)
{
Stop();
EventHelpers.Raise(null, ActiveSongChanged, EventArgs.Empty);
return;
}
}
MoveNext();
}
///
/// Resumes a paused song.
///
public static void Resume()
{
if (State != MediaState.Paused)
return;
PlatformResume();
State = MediaState.Playing;
}
///
/// Stops playing a song.
///
public static void Stop()
{
if (State == MediaState.Stopped)
return;
PlatformStop();
State = MediaState.Stopped;
}
///
/// Stops currently playing song, moves to the next song in the queue of playing songs and plays it.
///
///
///
/// If the current song is the last song in the queue, will stay on current song
///
///
public static void MoveNext()
{
NextSong(1);
}
///
/// Stops currently playing song, moves to the previous song in the queue of playing songs and plays it.
///
///
///
/// If the current song is the first song in the queue, will stay on current song
///
///
public static void MovePrevious()
{
NextSong(-1);
}
private static void NextSong(int direction)
{
Stop();
if (IsRepeating && _queue.ActiveSongIndex >= _queue.Count - 1)
{
_queue.ActiveSongIndex = 0;
// Setting direction to 0 will force the first song
// in the queue to be played.
// if we're on "shuffle", then it'll pick a random one
// anyway, regardless of the "direction".
direction = 0;
}
var nextSong = _queue.GetNextSong(direction, IsShuffled);
if (nextSong != null)
PlaySong(nextSong, null);
EventHelpers.Raise(null, ActiveSongChanged, EventArgs.Empty);
}
}
}