WPF,Silverlight与XAML读书笔记第四十二 - 多媒体支持之音、视频和语音

说明:本系列基本上是《WPF揭秘》的读书笔记。在结构安排与文章内容上参照《WPF揭秘》的编排,对内容进行了总结并加入一些个人理解。

 

音频

在WPF中播放音频有以下几种方式:

  • SoundPlayer
  • MediaPlayer
  • SoundPlayerAction
  • MediaElement和MediaLine

 

SoundPlayer

    SoundPlayer是随.NET Framework 2.0一起发布的类,其实对Win32 PlaySound API的一个封装,这是在WPF中播放声音最简单的方式,所以其也有一系列限制。

  • 仅支持wave格式音频文件
  • 不支持同时播放多个音频
  • 无法控制音量

下面是一段简单的示例:

1 SoundPlayer player = new SoundPlayer("lily.wav"); 
2 player.Play();

    SoundPlayer构造函数接受一个文件名或一个URL。上面代码中调用的Play方法将会在另一个线程上异步播放声音。另一个方法PlaySync在当前线程上播放该声音,PlayLooping会实现循环异步播放声音,直至显式调用Stop方法停止为止。

    默认情况下,SoundPlayer会在第一次调用Play相关方法时才加载文件,但由于文件可能存在于网络上,由于缓冲文件等原因可能造成播放前的停顿。解决这个问题,我们可以手动调用Load或LoadAsync方法提前加载文件。

    使用位于System.Media下的SystemSounds类可以播放一些系统声音。SystemSounds包含很多类,如Beep,Exclamation,Question等表示不同的系统声音,这些属性都是SystemSound类型,可以直接调用它们的Play方法异步非循环的播放声音。

 

SoundPlayerAction

    这个类最大的作用就是可以将SoundPlayer无缝的融入XAML,在不用编写C#代码的情况下播放声音。SoundPlayerAction派生自TriggerAction,我们可以直接使用它来设置Trigger的Actions属性。下面的例子中我们给按钮添加一个事件触发器,实现在点击按钮时播放一段声音。

 1 <Button>A Button With Sounds
 2     <Button.Triggers>
 3         <EventTrigger RoutedEvent="Button.Click">
 4             <EventTrigger.Actions>
 5                 <SoundPlayerAction Source="click.wav"/>
 6             </EventTrigger.Actions>
 7         </EventTrigger>
 8         <EventTrigger RoutedEvent="Button.MouseEnter">
 9             <EventTrigger.Actions>
10                 <SoundPlayerAction Source="hover.wav"/>
11             </EventTrigger.Actions>
12         </EventTrigger>
13     </Button.Triggers>
14 </Button>

同样使用这个类有更多的限制,你甚至不能循环播放或预先加载声音。

 

MediaPlayer

    这个类位于System.Windows.Media命名空间,它是WPF中一个可选的较高级的音频播放功能工具。这个类基于Windows Media Player构建,支持Windows Media Player所支持的多种音频格式(当然其也支持视频,在介绍WPF中视频一节还会再次深入讲述这个类)。通过多个Media Player的实例,可以实现音频同时播放(一个实例同一时间只能播放一个文件)。float类型的Volumn属性用于调整音量,范围由0到1,默认值是0.5。下面列举更多的音频控制方式:

  • 当CanPause属性为true时,可以通过Pause方法停止音频。
  • 设置IsMuted为true可以将音频静音
  • 通过设置Balance来调整左右扬声器平衡
  • 通过设置SpeedRatio来改变支持变速的音频格式的音频的速度,这个值即表示速度变化的倍数,默认值为1.0
  • 通过NaturalDuration属性可以得到音频文件的长度,Position属性可以得到当前播放的位置。

照例给出一段简单的示例代码:

1 MediaPlayer player = new MediaPlayer();
2 player.Open(new Uri("moon.wma", UriKind.Relative));
3 player.Play();

如代码所示,我们用Open打开文件,Play播放文件。相应的还有Pause,Stop和Close来控制文件播放。

 

视频

    WPF对视频的支持也是通过前面介绍的Media Player,MediaElement级MediaTimeLine来实现。所以Windows Media Player所支持的视频格式如wmv,avi,mpg都可以在WPF中使用。但在程序中使用MediaPlayer类时,要保证最终运行的系统中安装有Windows Media Player 10或更高版本。有关Media Element的话题同样见多媒体控件部分。

 

语音

.NET Framework中新增了一系列语音相关的API,位于System.Speech命名空间下,这些类主要支持语音识别语音合成,这套API并没有为WPF做特殊处理,即没有添加依赖属性,路由事件等特性,所以我们只能在C#代码中使用这些类。

语言合成由Microsoft SAPI SDK来支持。SAPI SDK中包含了几套不同的语音,使合成语音有不同的效果。仍然通过一段代码来展示语音合成。

1 SpeechSynthesizer synthesizer = new SpeechSynthesizer();
2 synthesizer.Speak("测试语音合成");

要使这段代码工作,需要引用System.Speech.dll,并引用System.Speech.Synthesis命名空间。合成语音的声音、速度和音量可以在控制面板语音合成项中设置。

使用SpeakAsync方法可以异步播放合成语言,此时也可以通过设置SpeechSynthesizer的Rate和Volumn属性来改变声音的速度和音量。Rate的范围是-10到10,而Volumn的范围是0到100。通过调用SpeakAsyncCancelAll取消处于等待状态的语音合成。

调用SelectVoice方法可以改变合成语音使用的声音,如代码:

1 synthesizer.SelectVoice("Microsoft Sam");

或者通过指定性别和年龄来选择一个声音,如:

1 synthesizer.SelectVoiceByHints(VoiceGender.Female,VoiceAge.Senior);

上面介绍的所有例子,转换后的语音会默认输出到扬声器,通过以下代码你可以将其输出到一个.wav文件:

1 synthesizer.SetOutputToWaveFile(@"C:\mySpeech.wav");

而如下的代码可以将输出恢复到扬声器:

1 synthesizer.SetOutputToDefaultAudioDevice();

 

    新的Speech API支持W3C标准 – 语言合成标记语言SSML。通过SSML,可以将复杂的语言封装在一个单独的模块中。通过调用SpeakSsml和SpeakSsmlAsync方法可以向SpeechSynthesizer传入SSML内容,SSML是标准的XML格式文件,我们可以通过PromptBuilder以编程方式轻松的构件SSML。下面是一段PromptBuilder的使用示例:

 1 //构造PromptBuilder
 2 PromptBuilder promptBuilder = new PromptBuilder();
 3 //普通文本
 4 promptBuilder.AppendText("A common text Line");
 5 //逐字读出每一个字母
 6 promptBuilder.AppendTextWithHint("WPF", SayAs.SpellOut);
 7 //如下可以更好的阅读一个时间
 8 promptBuilder.AppendTextWithHint(DateTime.Now.ToString("hh:mm"), SayAs.Time);
 9 //停顿
10 promptBuilder.AppendBreak(new TimeSpan(0, 0, 2));
11 //单独设置一段文本的语音效果,也可使文本形成段落效果
12 promptBuilder.StartVoice("Microsoft Sam");
13 promptBuilder.StartStyle(new PromptStyle(PromptRate.ExtraFast));
14 promptBuilder.AppendText("A special text line");
15 promptBuilder.EndStyle();
16 promptBuilder.EndVoice();
17 //甚至可以这样播放一段SSML
18 promptBuilder.AppendAudio("sample.wav");
19 //传入SpeechSynthesizer
20 SpeechSynthesizer synthesizer = new SpeechSynthesizer();
21 synthesizer.SpeakAsync(promptBuilder);

如代码,我们将PromptBuilder对象直接传给Speak/SpeakAsync中接受PromptBuilder的重载。通过PromptBuilder的ToXml()方法,我们可以得到以xml表示的SSML。作为一个W3C标准XML格式的SSML可以很方便的用于.NET以外的平台。

Speak与SpeakAsync还有一个接受FilePrompt的重载,通过这个重载我们可以方便的将多种格式的文件传入SpeechSynthesizer,下面代码展示了部分FilePrompt的构建:

1 synthesizer.SpeakAsync(new FilePrompt("text.txt", SynthesisMediaType.Text)); 
2 synthesizer.SpeakAsync(new FilePrompt("content.ssml", SynthesisMediaType.Ssml)); 
3 synthesizer.SpeakAsync(new FilePrompt("sound.wav", SynthesisMediaType.WaveAudio));

这里我们看到了第二种实现在文本转语言中播放wav的方法。

 

语音识别

语音识别与上文语言合成进行恰好相反的工作,其由音频中提取语言,并将其转换为文本,要使用语音识别需要计算机中安装有语音识别引擎,Windows Vista自带了一个语音识别引擎,Office Xp之后的版本也带有一个语音识别引擎。

要在代码中实现语音识别也要先添加对System.Speech.dll引用,不同的是这里要引用System.Speech.Recognition命名空间。下面代码给出一个最基本的使用的范例:

1 SpeechRecognizer recognizer = new SpeechRecognizer(); 
2 recognizer.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(recognizer_SpeechRecognized);

当语音被识别后,事件被触发,回调函数被调用,在其中可以处理识别到的文本:

1 void recognizer_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
2 {
3     textBox.Text += e.Result.Text;
4 }

提示:在一个系统上第一次使用语音识别时要先完成一个语音识别向导,另外,在Windows Vista以上版本中,语音识别被集成到任何一个可以获取输入的文本框(WPF或WinForm等程序中的)中,只需要对着麦克风讲话系统就会将识别结果填入文本框中。

 

使用SRGS

    语音识别规范(SRGS – Speech Recognition Grammar Specification)是W3C标准,你可以定义一个SRGS语法,通过其方便SpeechRecognizer捕获一些有效的输入,并忽略无意义的结果。SRGS也被定义成标准的XML格式,在.NET中使用SRGS,我们需要先构造一个SrgsDocument对象(所有SRGS相关的对象都定义于System.Speech.Recognition.SrgsGrammar命名空间中),下面的代码中我们定义了一个SrgsDocument并将其传入SpeechRecognizer:

1 SpeechRecognizer recognizer = new SpeechRecognizer(); 
2 SrgsDocument doc = new SrgsDocument("grammar.xml"); 
3 recognizer.LoadGrammar(new Grammar(doc));

上面的例子中,Srgs来自xml文件,我们也可以在内存中定义并使用SRGS。下面的代码中我们定义了一个SrgsDocument,这个文档表示由输入音频中匹配stop和go两条命令。

1 SpeechRecognizer recognizer = new SpeechRecognizer();
2 SrgsDocument doc = new SrgsDocument();
3 SrgsRule command = new SrgsRule("command",new SrgsOneOf("stop","go"));
4 doc.Rules.Add(command);
5 doc.Root = command;
6 recognizer.LoadGrammar(new Grammar(doc));

 

使用GrammarBuilder

    如同我们可以使用PromptBuilder方便的构建SSML,.NET中也提供了一个GrammarBuilder对象来定义SRGS;以解决手工编写SRGS xml或使用SrgsGrammar API定义SRGS都很麻烦的问题,下面的代码使用GrammerBuilder实现了与上面代码等价的功能:

1 SpeechRecognizer recognizer = new SpeechRecognizer();
2 GrammarBuilder builder = new GrammarBuilder(new Choices("stop","go"));
3 recognizer.LoadGrammar(new Grammar(builder));

 

VideoBrush

通过使用视频刷可以对一个区域使用视频进行填充,这个画刷SourceName的值需要设置为一个MediaElement控件的x:Name属性。这个MediaElement用来加载视频,我们需要其隐藏并不响应任何鼠标事件,这可以通过将MediaElement的透明度设置为0并将IsHitTestVisible属性设置为false来做到。在加载视频后我们可以通过Stretch等属性控制视频刷的效果。

下面的示例中,我们通过视频刷绘制文本框的前景色

1 <TextBlock FontFamily="Courier New" FontSize="72" FontWeight="Bold" TextWrapping="Wrap" Text="Hello">
2     <TextBlock.Foreground>
3         <VideoBrush SourceName="vid" />
4     </TextBlock.Foreground>
5 </TextBlock>

关于MediaElement,其对音频及视频的支持统一放到控件之多媒体控件一节介绍

 

本文完

 

参考:

《WPF揭秘》

posted @ 2013-06-09 09:37  hystar  阅读(372)  评论(0编辑  收藏  举报