• Windows Phone 录制音频和保存录音开发
    时间:2012-03-11   作者:佚名   出处:互联网

    Windows Phone是微软发布的一款手机操作系统,它将微软旗下的Xbox LIVE游戏、Zune音乐与独特的视频体验整合至手机中。2010年10月11日晚上9点30分,微软公司正式发布了智能手机操作系统Windows Phone,同时将谷歌的Android和苹果的IOS列为主要竞争对手。2011年2月,诺基亚与微软达成全球战略同盟并深度合作共同研发,建立庞大的生态系统。Windows Phone 8将采用和Windows 8相同的内核。本文将给大家介绍 Windows Phone 录制音频和保存录音制作

    一、录制音频
    Windows Phone 提供的访问麦克风的类为 Microsoft.Xna.Framework.Audio.Microphone ,该类属于 XNA Framework , 若要在 Silverlight 中访问 Windows Phone 麦克风,同样需要使用此类。所以需要添加引用 Microsoft.Xna.Framework。
    1.声明局部变量,获取麦克风单例。

    2.由于在XNA中每33fp就会更新画面一次,但在Silverlight Application并没有这样的机制,为了确保录音的功能持续的更新状态与进行撷取动作,因此,需要透过指定一个定期执行 FrameworkDispatcher.Update() 的事件。
            //设置定时器
            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = TimeSpan.FromMilliseconds(33);
            timer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
            timer.Start();

     3.设置录音相关信息,启动录音。
            //设置1秒的缓存区,没获取1秒音频就会调用一次BufferReady事件
            microphone.BufferDuration = TimeSpan.FromMilliseconds(1000);
            //分配1秒音频所需要的缓存区
            buf = new byte[microphone.GetSampleSizeInBytes(microphone.BufferDuration)];
            audioStream = new MemoryStream();
            //BufferReady事件
            microphone.BufferReady += new EventHandler<EventArgs>(microphone_BufferReady);
            //启动录音
            microphone.Start();

    4.实现 BufferReady 事件处理程序。该处理程序将麦克风的数据复制到缓冲区中并将该缓冲区写入一个流。
            void microphone_BufferReady(object sender, EventArgs e)
            {
                //将麦克风的数据复制到缓冲区中
                microphone.GetData(buf);
                //将该缓冲区写入一个流
                audioStream.Write(buf, 0, buf.Length);
            }

      5.停止录音
            //停止录音
            microphone.Stop();
            microphone.BufferReady -= new EventHandler<EventArgs>(microphone_BufferReady);
            audioStream.Flush();
            //将数据流转换为byte,recording中即为音频数据
            byte[] recording = audioStream.ToArray();
            audioStream.Dispose();

      6.播放录音
            //播放录音
            SoundEffect sound = new SoundEffect(audioStream.ToArray(), microphone.SampleRate, AudioChannels.Mono);
            sound.Play();

    通过录制的byte字节流数据,可以通过SoundEffect类播放,相当容易。但是如果想通过其他方式播放或在要到处音频数据,则需要将音频数据以文件的方式保存到独立存储中。

    保存音频

    录制好的音频要保存为文件,需要做相关格式转换。一般录音的格式为.WAV,下面就介绍如何将录音保存为WAV文件。
      1.在录制音频开始之前,首先要向音频流存储区audioStream中写入WAV文件头信息。即在调用microphone.Start()之前调用WriteWavHeader(audioStream, microphone.SampleRate),其中WriteWavHeader函数实现如下。


    WriteWavHeader
     1 /// <summary>
     2 /// 写wav文件头信息
     3 /// </summary>
     4 /// <param name="stream"></param>
     5 /// <param name="sampleRate"></param>
     6 public void WriteWavHeader(Stream stream, int sampleRate)
     7 {
     8     const int bitsPerSample = 16;
     9     const int bytesPerSample = bitsPerSample / 8;
    10     var encoding = System.Text.Encoding.UTF8;
    11
    12     // ChunkID Contains the letters "RIFF" in ASCII form (0x52494646 big-endian form).
    13     stream.Write(encoding.GetBytes("RIFF"), 0, 4);
    14
    15     // NOTE this will be filled in later
    16     stream.Write(BitConverter.GetBytes(0), 0, 4);
    17
    18     // Format Contains the letters "WAVE"(0x57415645 big-endian form).
    19     stream.Write(encoding.GetBytes("WAVE"), 0, 4);
    20
    21     // Subchunk1ID Contains the letters "fmt " (0x666d7420 big-endian form).
    22     stream.Write(encoding.GetBytes("fmt "), 0, 4);
    23
    24     // Subchunk1Size 16 for PCM.  This is the size of therest of the Subchunk which follows this number.
    25     stream.Write(BitConverter.GetBytes(16), 0, 4);
    26
    27     // AudioFormat PCM = 1 (i.e. Linear quantization) Values other than 1 indicate some form of compression.
    28     stream.Write(BitConverter.GetBytes((short)1), 0, 2);
    29
    30     // NumChannels Mono = 1, Stereo = 2, etc.
    31     stream.Write(BitConverter.GetBytes((short)1), 0, 2);
    32
    33     // SampleRate 8000, 44100, etc.
    34     stream.Write(BitConverter.GetBytes(sampleRate), 0, 4);
    35
    36     // ByteRate =  SampleRate * NumChannels * BitsPerSample/8
    37     stream.Write(BitConverter.GetBytes(sampleRate * bytesPerSample), 0, 4);
    38
    39     // BlockAlign NumChannels * BitsPerSample/8 The number of bytes for one sample including all channels.
    40     stream.Write(BitConverter.GetBytes((short)(bytesPerSample)), 0, 2);
    41
    42     // BitsPerSample    8 bits = 8, 16 bits = 16, etc.
    43     stream.Write(BitConverter.GetBytes((short)(bitsPerSample)), 0, 2);
    44
    45     // Subchunk2ID Contains the letters "data" (0x64617461 big-endian form).
    46     stream.Write(encoding.GetBytes("data"), 0, 4);
    47
    48     // NOTE to be filled in later
    49     stream.Write(BitConverter.GetBytes(0), 0, 4);
    50 }

     2.在录制音频结束的时候,才能确认录音文件大小的长度,此时需要修改WAV文件头部分信息。即在调用microphone.Stop()之后调用UpdateWavHeader(audioStream),其中

    UpdateWavHeader函数实现如下。
    UpdateWavHeader
     1 /// <summary>
     2 /// 更新wav文件头信息
     3 /// </summary>
     4 /// <param name="stream"></param>
     5 public void UpdateWavHeader(Stream stream)
     6 {
     7     if (!stream.CanSeek) throw new Exception("Can't seek stream to update wav header");
     8
     9     var oldPos = stream.Position;
    10
    11     // ChunkSize  36 + SubChunk2Size
    12     stream.Seek(4, SeekOrigin.Begin);
    13     stream.Write(BitConverter.GetBytes((int)stream.Length - 8), 0, 4);
    14
    15     // Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data.
    16     stream.Seek(40, SeekOrigin.Begin);
    17     stream.Write(BitConverter.GetBytes((int)stream.Length - 44), 0, 4);
    18
    19     stream.Seek(oldPos, SeekOrigin.Begin);
    20 }

    3.通过以上处理后的audioStream流已经是格式化后的WAV流。接下来只需要将audioStream流写入独立存储中(yu.wav)。

            //将数据流转换为byte,recording中即为音频数据
            byte[] recording = audioStream.ToArray();
            //独立存储文件处理
            using (IsolatedStorageFile myIsolatedStorage = IsolatedStorageFile.GetUserStoreForApplication())
            {
                try
                {
                    //打开文件
                    using (IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream("yu.wav", FileMode.Create, myIsolatedStorage))
                    {
                        fileStream.Write(recording, 0, recording.Length);
                    }
                }
                catch (Exception ex)
                {
                    //读取失败
                }
            }

    网友留言/评论

    我要留言/评论

    相关文章

    VC++中关于TCHAR,WCHAR,LPSTR,LPWSTR,LPCTSTR的解释:许多VC++ 程序员对于像TCHAR,LPCTSTR这样诡异的标识符感到非常迷惑。今天,我将尝试简短的把这团迷雾解释清楚。
    如何获取某个进程的主窗口以及创建进程的程序名?:在编写工具程序以及系统管理程序的时候。常常需要获取某个进程的主窗口以及创建此进程的程序名。获取主窗口的目的是向窗口发送各种消息。获取启动进程的程序名可以控制对进程的操作。但是有些进程往往有多个主窗口。你要的是哪一个主窗口呢?如果你用过Outlook程序,你就会发现它有多个主窗口,一个窗口列出收件箱和其它文件夹。如果你打开e-mail,便会有另外一个窗口显示信息。它们都是没有父窗口(或者说宿主窗口)的主窗口。运行一下Spy程序,你甚至会发现它们的窗口类名都相同:rctrl_renwnd32。资源管理器(Explorer.exe)也有不止一个主窗口。如图一所示,资源管理器有两个主窗口。一般来讲,想要获取主窗口,凭窗口的式样或类名,你没有什么办法知道哪一个窗口是真正意义上的主窗口。
    WINDOWS干干净净杀死进程编程:最近在写程序时碰到这样一个问题:我想将文件备份到网络驱动器上,但是有一些文件正在被其它程序使用,处于打开状态,而且是被独占打开,这时是没法对文件进行备份操作的。因此,要想备份这些文件,必须将打开它们的那些进程kill掉。那么如何干净地杀死这些打开文件的进程呢?相信看完本文后,自然会有办法解决!