65.9K
CodeProject 正在变化。 阅读更多。
Home

媒体播放器类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.85/5 (6投票s)

2010年11月8日

CDDL

4分钟阅读

viewsIcon

66907

downloadIcon

7419

一个使用 WindowsMediaPlayerClass 的高级媒体播放器类。支持交叉淡入/淡出。

引言

不久前,我发现自己在编写一个媒体播放器,因此也在寻找一种播放 MP3、Wav、midi 和其他文件类型的简单方法。我偶然发现了 WindowsMediaPlayerClass。它可以在 COM 库 WMP.dll 中找到。但是,它没有提供淡入或交叉淡出歌曲的功能。因此,我为它编写了一个更高级的包装类,它使用 WindowsMediaPlayerClass 对象来淡入和交叉淡出歌曲。

使用代码

要使用我的代码,请下载源文件并将 *Media Player.cs* 文件添加到你现有的/新的项目中。然后你必须添加对 COM 库 WMPLib 的引用。它的描述是 Windows Media Player,文件名是 *wmp.dll*。最后,确保引用的属性*嵌入互操作类型*设置为 false。这对于 VS2010 是必要的,我不确定早期版本。

该类使用两个 WindowsMediaPlayerClass 对象来播放文件和启用交叉淡入。当您使用该类时,它看起来好像只有一个播放器。但事件除外,我稍后会介绍。

该代码有五个主要方法:PlayPauseStopResumeFade。这些是唯一的公共方法。Play 相当基本;如果播放器暂停,它会恢复播放。如果播放器停止,它会播放指定的文件。根据您是否已将淡入设置为 true,播放器将仅使用播放器一进行播放,而无需淡入或交叉淡入。但是,如果您想要淡入/交叉淡入,播放器会在两个内部播放器之间交替,根据需要将它们淡入和淡出。

Pause 只是暂停当前的内部播放器。如果指定了淡出,它会启动淡出过程。Stop 执行相同的操作,只是它完全停止内部播放器,使其丢失当前位置。此外,Stop 会将播放器状态设置为已停止,因此后续对 Play 的第一次调用将播放新的指定文件。Pause 后的第一次调用将使播放器从上次位置继续播放当前曲目。Pause 后的第一次 Play 调用将调用 Resume,因此 ResumePlay 可以互换使用。最终方法 Fade 只是开始从当前音量淡入到新的指定音量。

有用的主要代码是 Crossfade,它在一个设定的时间内将一首歌曲淡入,将另一首歌曲淡出,从而产生线性交叉淡入效果。该代码使用一个每 500 毫秒滴答一次的计时器,以在每次发生滴答事件时,通过少量指定量调整两个内部播放器的音量。音量可能会在淡入/交叉淡入期间更改;但是,如果您这样做,在淡入/交叉淡入结束时会听到音量的突然跳跃。因此,建议不要在淡入/交叉淡入期间更改音量。

CrossfadeTimer_Tick 中的第一段代码确定这是否是交叉淡入的开始。如果是,则它以音量 0 启动新播放器,准备好淡入。代码如下

if (CrossfadeTotalRunTime <= 0)
{
    switch (StoppingPlayer)
    {
        case Players.Player1:
            PlayingPlayer = Players.Player2;
            Player2.volume = 0;
            Player2.URL = Player2Song;
            Player2.play();
            break;

        case Players.Player2:
            PlayingPlayer = Players.Player1;
            Player1.volume = 0;
            Player1.URL = Player1Song;
            Player1.play();
            break;
    }
}

下一段代码在交叉淡入发生时运行。它调整停止和播放播放器的音量,将播放淡入和停止淡出。这是交叉淡入。

else if(CrossfadeTotalRunTime < (CrossfadeTime * 1000))
{
    switch (PlayingPlayer)
    {
        case Players.Player1:
            {
                Player1.volume = (int)(CrossfadeVolumeAdjustment * 
                                 ((float)CrossfadeTotalRunTime / 1000));
                Player2.volume = (int)(Volume - (CrossfadeVolumeAdjustment * 
                                 (float)(CrossfadeTotalRunTime / 1000)));
            }
            break;

        case Players.Player2:
            {
                Player1.volume = (int)(Volume - (CrossfadeVolumeAdjustment * 
                                 ((float)CrossfadeTotalRunTime / 1000)));
                Player2.volume = (int)(CrossfadeVolumeAdjustment * 
                                 ((float)CrossfadeTotalRunTime / 1000));
            }
            break;
    }
}

最后一段代码在淡入结束时运行。它不会停止停止的播放器,而是让它运行直到其媒体结束。此外,它确保内部播放器的播放器音量与用户设置的音量相同。这就是在淡入/交叉淡入期间更改音量会在淡入结束时导致突然跳跃的原因。使用的最终音量只是设置的;如果不同,则两个音量之间没有平滑的淡入淡出。为了实现这一点,人们会增加交叉淡入/淡入的明显长度,并且比从一开始就不更改音量更难实现。

else if (CrossfadeTotalRunTime >= (CrossfadeTime * 1000))
{
    CrossfadeTimer.Enabled = false;
    CrossfadeTimer.Stop();
    InCrossfade = false;

    switch (PlayingPlayer)
    {
        case Players.Player1:
            Player1.volume = Volume;
            Player2.volume = 0;
            break;

        case Players.Player2:
            Player2.volume = Volume;
            Player1.volume = 0;
            break;
    }
}

最后要注意的是,即使您只是在外部调用了 Play,也会触发媒体结束等事件。这是因为每个播放器都会触发单独的事件,但在外部,它们看起来像一个播放器,这听起来令人困惑,但很有用,因为,例如,如果您正在播放交叉淡入曲目的播放列表,即使在下一首曲目开始播放后,您仍然会收到媒体结束事件。这允许更容易地编程播放计数和类似的歌曲属性。

© . All rights reserved.