C#.net winform 播放声音解决方案 Bass Library

Part 1

C#播放声音一直是很头疼的事
或者说从我刚学C# 脱离控制台开始 这个问题就困扰我N多年
然后我们不停的百度 基本就是如下方式:

1> System.Media 只能播放wav
2> winmm.dll API什么的很崩溃
3> wmp com组件 直接把控件拖进来 很傻瓜 也很凶残
4> AudioVideoPlayback.dll MDX的产物

总之....net基本没提供什么靠谱的播放声音方式
如果只是简单的播放提示音效 media命名空间应该足够用
不过对于咱这种无聊就造游戏提取器的人...应对的需求如下:

1> 灵活 无其他软件依赖(可以轻量 绿色发布)
2> 可编程性强(至少可以play pause stop setVolume)
3> 支持各种诡异的文件格式(wav mp3 ogg)
4> 支持流读取什么的..(先save成tempFile再load很折腾...)

最开始使用的是AudioVideoPlayback.dll这个库 应该说是受WzExtract影响
这个库很难找- - 为此我还下了各个版本的Managed DirectX SDK 好大一个坨....(而且最近一年之内我才知道它是干嘛用的...)

 

Part 2

播放mp3用它完全没问题 它也基本胜任我上述的要求
不过当我开发妖妖剑戟梦想提取器的时候我就蛋疼了...这东西无法播放ogg格式的声音文件
而且当时也有很多人表示mdx库在它们的工作站环境上无法正常工作...

百度之后找到一个奇怪的库叫libZPlay(http://libzplay.sourceforge.net/)以及它的.net接口
ogg格式播放搞定了 但是它有一个很鬼畜的设定叫“播放ogg的时候异常容易崩溃”
然后 orz....
(后来测试的时候发现是用timer频繁获取当前播放时间导致的.... 但是不频繁getCurrentTime也会崩溃 不过频率较低)

另外 libZPlay库倍儿大...2M的坨不符合我的编程美学...

总之现在手头还有相当一部分程序在使用这个库...

 

Part 3

后来学习了xna 我又碰到了播放声音这个蛋疼的问题...
(事实上我从开始学xna就带着很多蛋疼的问题...比如...我要求游戏使用通用格式资源和自定义格式资源 可绿色发布 可脱离.net发布 点点点...
然后目前我又多了两条需求:

5> 可多重播放(混音)
6> 支持3D声效有木有...

于是 我参考了OSU!(这是一个基于xna1.0的音乐游戏)的文件读取方式....
找到了bass.dll

 

Part 4

这文件倍儿熟 见过多少次了
第一次知道这东西是用来播放声音的才过去3个半月

它的发布网站是http://www.un4seen.com/

而且说实话它很萌
详细一点说的话就是它不到100kb就有这么强力的功能..
然后它的网站上提供了Bass.net以及一份非常详尽的API文档...
总之 这东西很神奇很有爱...

 

Part 5

C# 使用这个库 你需要下载Bass.dll库文件本体
以及Bass.net.dll这个工程
然后 注册一个免费的Licence 使用起来会很方便
地址为http://www.bass.radio42.com/
然后在你的程序第一句调用

Un4seen.Bass.BassNet.Registration("your email", "your regkey");

 

随bass.net下载的API文档讲述的非常非常详尽以至于我不想在这里放任何的代码...
因为只是C的dll的封装 函数都是静态的 调用起来也异常便利

总的来说 在bass里 常见的声音文件都被读取成为hStream 
加载声音用的是Bass.BASS_StreamCreateFile 卸载声音使用Bass.BASS_StreamFree
播放控制函数使用的是Bass.BASS_ChannelPlay、Bass.BASS_ChannelPause、Bass.BASS_ChannelStop

另外一个很萌的函数是Bass.BASS_PluginLoad
它可以让bass库自由加载符合bass接口的插件 以支持更多的文件格式... 而且能自己分辨格式...
总之我用它加载了一票插件...然后成功的把我的游戏提取器改造成了万能无损播放器....

 

实际上 在实际应用中 我对播放器做了一个很繁琐的封装

 

public interface ISoundPlayer : IDisposable
{
    bool Inited { get; }
    bool Init();
    void PreLoad(ISoundFile sound);
    void UnLoad();
    void Play();
    void Pause();
    void Resume();
    void Stop();
    bool AutoPlay { get; set; }
    int Volume { get; set; }
    double SoundPosition { get; set; }
    double SoundLength { get; }
    PlayState State { get; }
}

public enum PlayState
{
    Stopped = 0,
    Playing,
    Paused
}

public interface ISoundFile
{
    string FileName { get; }
    int StartPosition { get; }
    int Length { get; }
}


然后对Wz_Mp3实现ISoundFile接口 新建BassSoundPlayer继承自ISoundPlayer就OK了
接口实现可以在不改变界面和外围调用的情况下 自由改变底层实现方式

应该可以推测 bass库使用的是共享文件方式的流读取解码
不过有些插件读取错误的时候会锁定文件句柄 关闭程序才会释放...

32位和64位

因为bass.net实质上是调用的C API库 所以系统环境差异会让它挂掉
在bass论坛上可以找到64位的bass.dll以及若干插件
文件发布的时候分两个版本发布就OK了

在bass.net API文档里 也提供了如下的方式以供变通...

string targetPath ="";
if(Utils.Is64Bit)
    targetPath = Path.Combine(Application.StartupPath,"x64");
else
    targetPath = Path.Combine(Application.StartupPath,"x86");


// now load all libs manually
Bass.LoadMe(targetPath);
BassMix.LoadMe(targetPath);
...
loadedPlugIns = Bass.BASS_PluginLoadDirectory(targetPath);
...
// at the end of your application call this!
Bass.FreeMe(targetPath);
BassMix.FreeMe(targetPath);
...
foreach(int plugin in LoadedBassPlugIns.Keys)
    Bass.BASS_PluginFree(plugin);

 

Part 6

其实bass库很残念的是没有提供playEnd播放结束监视事件
不过bass.net里面自己封装了一个BassTimer 可以反复监视播放时间然后判断是否结束...(虽然觉得不太靠谱...)

事实上有了playEnd以后就可以有ProgressChanged事件...然后就封装的很美好了....

嗯 要playEnd干啥用...当然是做播放列表啊..

事实上可以用BASS_ChannelSetSync来附加一些事件 比如pos end等...详见文档...
于是这样可以达成很多目的了-w-

另外对于3D播放的音频格式也有诡异的要求
而且现在还没太清楚它的运作方式...

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页