C#:利用CSCore写一个轻量级音频播放器

一、前言

前段时间想用C#写一个音频播放器,找来找去找到一个音频开源库:CSCore,发现有挺多家网站采用了它的底层库,它支持的音频格式也挺全。

 

CSCore 是一个完全用 C# 编写的免费 .NET 音频库。 尽管它仍然是一个相当年轻的项目,但它提供了大量功能,例如播放或捕获音频、编码或解码许多不同的编解码器、效果等等。

CSCore 基于一个可扩展的架构,它允许您无需努力即可满足您的需求。 您可以构建音乐播放器、语音聊天、录音机等! 支持的平台:仅限 Windows、linux 和 mac 实验版(参见 https://github.com/filoe/cscore/tree/netstandard)。--摘自Github官网

参考了一下它的Demo,特此记录一下编写的过程。编写的时候可以参考它的在线文档

 二、编写

首先打开Visual Studio,打开项目-管理NuGet程序包,搜索CSCore并安装;

 支持.NET Framework 4.0及以上,在.NET Core中导入会提示不兼容,不过好像也可以正常用。

先封装一个MusicPlayer类

namespace AudioPlayer
{
    /// <summary>
    /// 封装音频播放器
    /// </summary>
    public class MusicPlayer : Component
    {
        private ISoundOut _soundOut;
        private IWaveSource _waveSource;

		public event EventHandler<PlaybackStoppedEventArgs> PlaybackStopped;
        /// <summary>
        /// 获取播放器的播放状态
        /// </summary>
        public PlaybackState PlaybackState
        {
            get
            {
                if (_soundOut != null)
                    return _soundOut.PlaybackState;
                return PlaybackState.Stopped;
            }
        }
        /// <summary>
        /// 目前播放音频的位置
        /// </summary>
        public TimeSpan Position
        {
            get
            {
                if (_waveSource != null)
                    return _waveSource.GetPosition();
                return TimeSpan.Zero;
            }
            set
            {
                if (_waveSource != null)
                    _waveSource.SetPosition(value);
            }
        }
        /// <summary>
        /// 获取播放音频的长度
        /// </summary>
        public TimeSpan Length
        {
            get
            {
                if (_waveSource != null)
                    return _waveSource.GetLength();
                return TimeSpan.Zero;
            }
        }
        /// <summary>
        /// 播放器的音量
        /// </summary>
        public int Volume
        {
            get
            {
                if (_soundOut != null)
                    return Math.Min(100, Math.Max((int)(_soundOut.Volume * 100), 0));
                return 100;
            }
            set
            {
                if (_soundOut != null)
                {
                    _soundOut.Volume = Math.Min(1.0f, Math.Max(value / 100f, 0f));
                }
            }
        }
        /// <summary>
        /// 读取音频文件地址
        /// </summary>
        /// <param name="filename"></param>
        public void Open(string filename)
        {
            CleanupPlayback();
            
            _waveSource =
                CodecFactory.Instance.GetCodec(filename)
                    .ToSampleSource()
                    .ToWaveSource();
            _soundOut = new WaveOut() {Latency = 100};
            _soundOut.Initialize(_waveSource);
			if (PlaybackStopped != null) _soundOut.Stopped += PlaybackStopped;
        }
        /// <summary>
        /// 播放
        /// </summary>
        public void Play()
        {
            if (_soundOut != null)
                _soundOut.Play();
        }
        /// <summary>
        /// 暂停
        /// </summary>
        public void Pause()
        {
            if (_soundOut != null)
                _soundOut.Pause();
        }
        /// <summary>
        /// 停止
        /// </summary>
        public void Stop()
        {
            if (_soundOut != null)
                _soundOut.Stop();
        }
        /// <summary>
        /// 释放设备和音频资源
        /// </summary>
        public void CleanupPlayback()
        {
            if (_soundOut != null)
            {
                _soundOut.Dispose();
                _soundOut = null;
            }
            if (_waveSource != null)
            {
                _waveSource.Dispose();
                _waveSource = null;
            }
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
            CleanupPlayback();
        }
    }
}

然后在主页面中实例化这个类

private readonly MusicPlayer _musicPlayer = new MusicPlayer();

设置一个“打开文件”按钮,Filter中是CSCore支持的音频格式,filename是音频文件的路径

private void button_selectfile_Click(object sender, EventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog
            {
                Filter = CodecFactory.SupportedFilesFilterEn
            };
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    filename = openFileDialog.FileName;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Could not open file: " + ex.Message);
                }
            }
        }

如果想要播放网络上的音频也可以在MusicPlayer类中这样编写

/// <summary>
/// 读取音频文件地址
/// </summary>
/// <param name="filename"></param>
public void Open(Uri uri)
{
    CleanupPlayback();
    _waveSource =
    CodecFactory.Instance.GetCodec(uri)
    .ToSampleSource()
    .ToWaveSource();
    _soundOut = new WaveOut() {Latency = 100};
    _soundOut.Initialize(_waveSource);
    if (PlaybackStopped != null) _soundOut.Stopped += PlaybackStopped;
}

设置一个播放按钮,按下后变成暂停按钮

        private void button_play_Click(object sender, EventArgs e)
        {
            if(_musicPlayer.PlaybackState != CSCore.SoundOut.PlaybackState.Playing)
            {
                if (!filename.Equals(String.Empty))
                {
                    try
                    {
                        if (_musicPlayer.Length.TotalMilliseconds - _musicPlayer.Position.TotalMilliseconds <= 50) _musicPlayer.Position = new TimeSpan(0);
                        _musicPlayer.Play();
                        button_play.Text = "暂停";
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show("播放失败:" + ex.Message);
                    }
                }
            }
            else
            {
                if (_musicPlayer.PlaybackState == CSCore.SoundOut.PlaybackState.Playing)
                {
                    _musicPlayer.Pause();
                    button_play.Text = "播放";
                }
            }
        }

设置一个停止按钮

        private void button_stop_Click(object sender, EventArgs e)
        {
            musicStop();
        }
        /// <summary>
        /// 音乐停止时的操作
        /// </summary>
        private void musicStop()
        {
            _musicPlayer.Stop();
            _musicPlayer.Position = new TimeSpan(0);
            button_play.Text = "播放";
        }

至此把音频的播放、暂停和停止功能实现了

音量控制在WinForm中可以和trackbar进行绑定,在WPF中和slider绑定;我设置trackbar的最大值为20,而MusicPlay类音量变化范围:0-100;

        private void trackbar_volume_Scroll(object sender, EventArgs e)
        {
            _musicPlayer.Volume = trackbar_volume.Value * 5;
        }

进度控制也是如此,新建一个trackbar,最大值为100,MusicPlayer类的播放进度范围:音频长度,Potison属性是TimeSpan类型

        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            int timenow = Convert.ToInt32(((trackBar1.Value * _musicPlayer.Length.TotalMilliseconds) / 100));
            System.TimeSpan timeSpan = new TimeSpan(
                ((timenow % (360000 * 60 * 24)) / (36000 * 60)),
                ((timenow % (360000 * 60)) / 360000),
                (timenow % 360000) / 60000,
                (timenow % 60000) / 1000,
                (timenow % 1000));
            _musicPlayer.Position = timeSpan;
        }

在播放的时候可以新建一个timer,将MusicPlayer的播放进度在trackbar上显示

     private void timer1_Tick(object sender, EventArgs e)
        {
            trackbar_volume.Value = _musicPlayer.Volume / 5;
            trackBar1.Value = (_musicPlayer.Position.TotalMilliseconds > 0 ? Convert.ToInt32(((_musicPlayer.Position.TotalMilliseconds * 100) / _musicPlayer.Length.TotalMilliseconds)) : 0);
        }

三、小结

写的时候踩了很多坑,由于MusicPlayer类我是从它的Demo里抄来的,刚开始代码没怎么看;后来发现音频播放的时候音质很差,没有立体音,翻了代码才发现_waveSource被转成了单声道,所以音频都没有立体音了。也许还有其他更好的音频库可以使用,不过我感觉CSCore的代码还是很轻便的;CSCore还有很多功能,有兴趣的可以去Github上看看它的Demo和在线文档。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值