最近在做一款软件,需要用到声音播放,同时实现背景音乐和音效的播放。在C#中声音的播放主要有六种方法:
1.播放系统事件声音
2.使用SoundPlayer
3.使用API函数播放
4.使用axWindowsMediaPlayer的COM组件来播放
5.Microsoft speech object Library
6.使用directX
具体的使用方式在网上都能找到,可参考believe209的文章,本文不再做复述。(C#播放声音【六种方法】_c# 播放声音-CSDN博客)
这里要说的是几种播放声音的测试结果,希望可以帮助在用到C#做声音播放应用的朋友。我们在开发应用的时候,常常需要同时播放多种声音,比如同时播放背景音乐和音效。这几种播放方式同时使用可能会发生冲突,停止当前播放声音,只去播放一种声音,达不到应用效果,我怀疑几种播放方式都是调用的SoundPlayer来进行播放的;我也遇到过在测试环境下播放声音正常,程序打包后无法正常播放的情况;特别是采用axWindowsMediaPlayer的COM组件来播放,文件装载延时大约2秒左右,影响软件体验效果,如果对延时要求不高的播放场景可以选择这种方式。在实际编程中,可根据不的需要选择不同的播放组合方式。
我运用的是SoundPlayer和directX两种方式播放声音,效果较好,后面我把调用方式和遇到的问题都附在文章后面。
一、播放系统事件声音,简单语句可以实现声音播放。缺点:只能播放系统定义的声音,无法进行属性设置和修改,播放方式固定。
System.Media.SystemSounds.Question.Play();
二、.使用SoundPlayer
SoundPlayer player = new SoundPlayer();
player.SoundLocation = @"C:\test.wav"; //声音文件路径
// Application.StartupPath + @”\ test.wav” // Debug文件夹
player.Load(); //加载声音
player.Play(); //启用新线程播放
//player.PlayLooping(); //循环播放模式
缺点:不能同时播放声音,只能播放wav声音文件,可用来循环播放背景音乐。
三、使用API函数播放
通过调用外部winmm.dll方式播放声音,winmm.dll有三个声音播放函数,mciSendString可以播放mp3文件,其它函数也只有播放wav。这种方式在调试状态可以和SoundPlayer同时播放声音文件,不知道是不是配置问题,打包后无法播放声音,没有找到原因,如果有知道原因的大神可以在评论区告知一下,谢谢!
[DllImport("winmm.dll", SetLastError = true)]
static extern bool PlaySound(string pszSound, UIntPtr hmod, uint fdwSound);
[DllImport("winmm.dll", SetLastError = true)]
static extern long mciSendString(string strCommand,
StringBuilder strReturn,int iReturnLength, IntPtr hwndCallback);
[DllImport("winmm.dll")]
private static extern long sndPlaySound(string lpszSoundName, long uFlags);
四、使用axWindowsMediaPlayer的COM组件来播放
如果已添加了组件。工具箱->组件-> Windows Media Player,把Windows Media Player控件拖放到Winform窗体中。
如查没有添加,在左侧打开“工具箱”,在“工具箱”内点右键,选择右键菜单“选择项”,在“选择工具箱项“窗口中,选择“COM组件”项,下拉到“Windows Media Player”,在单选框上打上勾,点击确定后组件被加入到工具箱中。如果只需要播放声音,将“Windows Media Player”的Visible属性设置为false即可。
axWindowsMediaPlayer1.URL = "123.mp3"; //不同版本设置有所不同
axWindowsMediaPlayer1.Ctlcontrols.play();
axWindowsMediaPlayer1.Ctlcontrols.Play 播放
axWindowsMediaPlayer1.Ctlcontrols.Stop 停止
axWindowsMediaPlayer1.Ctlcontrols.Pause 暂停
axWindowsMediaPlayer1.settings.playCount 文件播放次数
axWindowsMediaPlayer1.settings.balance 声道
axWindowsMediaPlayer1.settings.volume 音量
axWindowsMediaPlayer1.settings.mute 静音
五、Microsoft speech object Library
在项目上单击右键菜单,“添加”->“引用“,打开引用管理器,在”COM“项目中找到“Microsoft speech object Library”,点击“确定”。
public voidPlaySound(string FileName){
SpeechLib.SpVoiceClass Sp = new SpeechLib.SpVoiceClass();
SpeechLib.SpFileStreamClass SpFs = new SpeechLib.SpFileStreamClass();
SpFs.Open(FileName, SpeechLib.SpeechStreamFileMode.SSFMOpenForRead,true);
SpeechLib.ISpeechBaseStream Istream = SpFs as SpeechLib.ISpeechBaseStream;
Sp.SpeakStream(Istream, SpeechLib.SpeechVoiceSpeakFlags.SVSFIsFilename);
SpFs.Close();
}
Microsoft speech object Library可以将文字转换为语音做语音功能,实现语音播报,也可以将语音识别为文字,很强大的东东,拿来播放声音文件个人感觉有点大材小用。
六、使用directX
这个比较复杂,网上大多讲得比较简单,在使用过程中遇到问题最多。
1.下载链接:微软官方下载链接
https://www.microsoft.com/en-us/download/details.aspx?id=6812
2.下载后运行安装。安装后的目录结构如下
问题一 :安装后命名空间无效 :具体方法:
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;
1.安装SDK之后
他默认的位置在
C:\Windows\Microsoft.NET\DirectX for Managed Code
或C:\WINDOWS\Microsoft.NET\Managed DirectX
不同版本安装文件夹名不一样
2.把里面相应版本的Microsoft.DirectX.Direct3DX.Dll都复制到,这需要与VS使用的运行环境版本文件夹位置一致
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1
或C:\Program Files\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0
3.在项目里面就可以添加引用了,这时就不会报错。
问题二 :调试运行程序卡死 解决办法:
修改配置文件App.config,修改方法如下:
原App.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
修改后的App.config,添加红色字体部分
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/>
</startup>
</configuration>
问题三: 调试报错为托管程序锁定 解决方案:
正尝试在 OS 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码,这样做会导致应用程序挂起。
把VS菜单的 调试->窗口->异常设置->Managed Debuggin Assistants->LoaderLock 的选中状态去掉。如图
问题4:System.TypeInitializationException
该错误是因为系统没有检测到麦克风引起,所以解决方法是
- 在程序中增加异常处理机制,捕捉异常,及时处理并做相应提示。
- 插入麦克风,或者启用虚拟麦克风
我采用第一种方法,用try异常过滤器忽略掉系统检测
public static Device dv; //建立设备
public static SecondaryBuffer buf; //设置缓冲对像
public static void mciPlay(string YXfilename)
{
try
{
dv = new Device();
dv.SetCooperativeLevel(new UF(), CooperativeLevel.Normal);//设置设备协作级别 必须设置,否则无播放声音
buf = new SecondaryBuffer(YXfilename, dv);//(YXfilename, dv); //开辟缓冲区
buf.Volume = 0;
buf.Play(0, BufferPlayFlags.Default); //第一个参数表示优先级别,0是最低的。第2个参数是播放方式,这里是循环播放。
}
catch { }
}
问题5:调试运行DLL版本不一致,编译器会报错,还需要在App.config文件中加入相应的版本号
有的说将解决方案平台修改一下,X64 改为 X86 ,我试过没什么作用。或许有人通过修改也解决了这个问题。
在引用DLL文件属性栏中,将复制本地设置为“true”,编译后,系统自动将DLL文件添加到DeBug文件夹里。