当当当上课啦!小伙伴们准备好了吗?我们继续接着讲上节课的内容! 获取音频数据 虽然KinectAudioSource类的最主要作用是为语音识别引擎提供音频数据流,但是它也可以用于其他目的。他还能够用来录制wav文件。下面的示例将使用KinectAudioSource来开发一个音频录音机。使用这个项目作为录音机,读者可以修改Kinectsdk中KinectAudioSource的各个参数的默认值的来了解这些参数是如何控制音频数据流的产生。 使用音频数据流 虽然使用的是Kinect的音频相关类,而不是视觉元素类,但是建立一个Kinect音频项目的过程大致是类似的。 1.创建一个名为KinectAudioRecorder的WPF应用项目。 2.添加对Microsoft.Kinect.dll和Microsoft.Speech.dll的引用。 3.在MainWindows中添加名为Play,Record和Stop三个按钮。 4.将主窗体的名称改为“AudioRecorder” 在VS的设计视图中,界面看起来应该如下: 令人遗憾的是,C#没有一个方法能够直接写入wav文件。为了能够帮助我们生成wav文件,我们使用下面自定义的RecorderHelper类,该类中有一个称之为WAVFORMATEX的结构,他是C++中对象转换过来的,用来方便我们对音频数据进行处理。该类中也有一个称之为IsRecording的属性来使得我们可以停止录制。类的基本结构,以及WAVFORMATEX的结构和属性如下。我们也需要初始化一个私有名为buffer字节数组用来缓存我们从Kinect接收到的音频数据流。 classRecorderHelper { staticbyte[]buffer=newbyte[]; staticbool_isRecording; publicstaticboolIsRecording { get { return_isRecording; } set { _isRecording=value; } } structWAVEFORMATEX { publicushortwFormatTag; publicushortnChannels; publicuintnSamplesPerSec; publicuintnAvgBytesPerSec; publicushortnBlockAlign; publicushortwBitsPerSample; publicushortcbSize; } } 为了完成这个帮助类,我们还需要添加三个方法:WriteString,WriteWavHeader和WriteWavFile方法。WriteWavFile方法如下,方法接受KinectAudioSource和FileStream对象,从KinectAudioSource对象中我们可以获取音频数据,我们使用FileStream来写入数据。方法开始写入一个假的头文件,然后读取Kinect中的音频数据流,然后填充FileStream对象,直到_isRecoding属性被设置为false。然后检查已经写入到文件中的数据流大小,用这个值来改写之前写入的文件头。 publicstaticvoidWriteWavFile(KinectAudioSourcesource,FileStreamfileStream) { varsize=0; //writewavheaderplaceholder WriteWavHeader(fileStream,size); using(varaudioStream=source.Start()) { //chunkaudiostreamtofile while(audioStream.Read(buffer,0,buffer.Length)0_isRecording) { fileStream.Write(buffer,0,buffer.Length); size+=buffer.Length; } } //writerealwavheader longprePosition=fileStream.Position; fileStream.Seek(0,SeekOrigin.Begin); WriteWavHeader(fileStream,size); fileStream.Seek(prePosition,SeekOrigin.Begin); fileStream.Flush(); } publicstaticvoidWriteWavHeader(Streamstream,intdataLength) { using(MemoryStreammemStream=newMemoryStream(64)) { intcbFormat=18; WAVEFORMATEXformat=newWAVEFORMATEX() { wFormatTag=1, nChannels=1, nSamplesPerSec=, nAvgBytesPerSec=, nBlockAlign=2, wBitsPerSample=16, cbSize=0 }; using(varbw=newBinaryWriter(memStream)) { WriteString(memStream,RIFF); bw.Write(dataLength+cbFormat+4); WriteString(memStream,WAVE); WriteString(memStream,fmt); bw.Write(cbFormat); bw.Write(format.wFormatTag); bw.Write(format.nChannels); bw.Write(format.nSamplesPerSec); bw.Write(format.nAvgBytesPerSec); bw.Write(format.nBlockAlign); bw.Write(format.wBitsPerSample); bw.Write(format.cbSize); WriteString(memStream,data); bw.Write(dataLength); memStream.WriteTo(stream); } } } staticvoidWriteString(Streamstream,strings) { byte[]bytes=Encoding.ASCII.GetBytes(s); stream.Write(bytes,0,bytes.Length); } 使用该帮助方法,我们可以开始建立和配置KinectAudioSource对象。首先添加一个私有的_isPlaying布尔值来保存是否我们想要播放录制的wav文件。这能够帮助我们避免录音和播放功能同事发生。除此之外,还添加了一个MediaPlayer对象用来播放录制好的wav文件。_recodingFileName用来保存最近录制好的音频文件的名称。代码如下所示,我们添加了几个属性来关闭和开启这三个按钮,他们是:IsPlaying,IsRecording,IsPlayingEnabled,IsRecordingEnabled和IsStopEnabled。为了使得这些对象可以被绑定,我们使MainWindows对象实现INotifyPropertyChanged接口,然后添加一个NotifyPropertyChanged事件以及一个OnNotifyPropertyChanged帮助方法。 在设置各种属性的逻辑中,先判断IsRecording属性,如果为false,再设置IsPlayingEnabled属性。同样的先判断IsPlaying属性为是否false,然后在设置IsRecordingEnabled属性。前端的XAML代码如下: Windowx:Class=KinectRecordAudio.MainWindow xmlns=白癜风中医医院北京治疗白癜风医院哪家好
|