zoukankan      html  css  js  c++  java
  • C#实现麦克风採集与播放

    在网络聊天系统中。採集麦克风的声音并将其播放出来。是最基础的模块之中的一个。本文我们就介绍怎样高速地实现这个基础模块。

    一. 基础知识

      有几个与声音採集和播放相关的专业术语必需要先了解一下,否则。后面的介绍将无法展开。语音採集指的是从麦克风採集音频数据。即声音样本转换成数字信号。

    其涉及到几个重要的參数:採样率、採样位数、声道数。

      简单的来说:

           採样率:即採样频率,就是在1秒内进行採集动作的次数。

           採样位数:又叫採样深度。就是每次採集动作得到的数据长度,即使用多少个bit来记录一个样本。

           声道数:通常是单声道或双声道(立体声)。普通的麦克风採集差点儿都是单声道的。

      这样。1秒钟採集得到的声音数据的大小为(单位byte):(採样频率×採样位数×声道数×时间)/8。

      音频帧:通常一个音频帧的时长为10ms,即每10ms的数据构成一个音频帧。假设:採样率16k、採样位数16bit、声道数1,那么一个10ms的音频帧的大小为:(16000*16*1*0.01)/8 = 320 字节。计算式中的0.01为秒。即10ms

    二. 怎样採集、播放?

      假设直接基于底层的DirectX来进行麦克风的採集与播放。那将是十分繁琐的。

    好在我们有现成的组件来完毕这个工作。MCapture 用于採集硬件设备(如麦克风、摄像头、声卡、屏幕等)。MPlayer 用于播放採集到的数据。

    1.採集麦克风

      MCapture提供了IMicrophoneCapturer。用于採集麦克风输入的声音。其每隔20ms触发一次AudioCaptured事件,通过事件的參数byte[]暴露这20ms採集得到的数据。

      IMicrophoneCapturer 相关採集參数的值是这种:

           採样频率:16000,採样位数:16bit。声道数:1。

           所以,依照上面的公式进行计算,我们能够得到AudioCaptured事件的參数byte[]的长度为640。

    2. 播放声音数据

      MPlayer提供了IAudioPlayer,用于播放声音数据。在创建IAudioPlayer实例时,要正确的设置採样频率、採样位数、声道数这些參数的值。假设它们与即将要播放的声音数据的特征不一致,播放将出现错误。

      我们在拿到MCapture採集的声音数据后,将其提交给IAudioPlayer的Play方法进行播放就可以。

    三.Demo实现

      在有了前面的介绍作为基础后,接下来实现麦克风的採集和播放就相当简单了。在接下来的demo中。不仅演示了播放从麦克风採集到的声音,并且多加了一个功能。就是直接播放wav声音文件,这些实现都是相当简单的。  

    复制代码
        public partial class Form1 : Form
        {
            private IAudioPlayer audioPlayer;
            private IMicrophoneCapturer microphoneCapturer;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            private void button_mic_Click(object sender, EventArgs e)
            {
                try
                {
                    this.microphoneCapturer = CapturerFactory.CreateMicrophoneCapturer(int.Parse(this.textBox_mic.Text));
                    this.microphoneCapturer.AudioCaptured += new ESBasic.CbGeneric<byte[]>(microphoneCapturer_AudioCaptured);
                    this.audioPlayer = PlayerFactory.CreateAudioPlayer(int.Parse(this.textBox_speaker.Text), 16000, 1, 16, 2);
                    this.microphoneCapturer.Start();
    
                    this.label_msg.Text = "正在採集麦克风,并播放 . . .";
                    this.label_msg.Visible = true;
                    this.button_wav.Enabled = false;
                    this.button_mic.Enabled = false;
                    this.button_stop.Enabled = true;
                }
                catch (Exception ee)
                {
                    MessageBox.Show(ee.Message);
                }
            }
    
            void microphoneCapturer_AudioCaptured(byte[] audioData)
            {
                if (this.audioPlayer != null)
                {
                    this.audioPlayer.Play(audioData);
                }
            }
    
            private void button_wav_Click(object sender, EventArgs e)
            {
                try
                {
                    string path = ESBasic.Helpers.FileHelper.GetFileToOpen2("请选择要播放的wav文件", AppDomain.CurrentDomain.BaseDirectory, ".wav");
                    if (path == null)
                    {
                        return;
                    }
    
                    AudioInformation info = PlayerFactory.ParseWaveFile(path);
                    if (info.FormatTag != (int)WaveFormats.Pcm)
                    {
                        MessageBox.Show("只支持PCM编码方式的语音数据!");
                        return;
                    }
    
                    int secs = info.GetTimeInMsecs() / 1000; //声音数据的播放时长
                    this.audioPlayer = PlayerFactory.CreateAudioPlayer(int.Parse(this.textBox_speaker.Text), info.SampleRate, info.ChannelCount, info.BitsNumber, secs + 1);
    
                    this.audioPlayer.Play(info.AudioData);
    
                    this.label_msg.Text = "正在播放wav文件 . . .";
                    this.label_msg.Visible = true;
                    this.button_wav.Enabled = false;
                    this.button_mic.Enabled = false;
                    this.button_stop.Enabled = true;
                }
                catch (Exception ee)
                {
                    MessageBox.Show(ee.Message);
                }
            }
    
            private void Form1_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (this.microphoneCapturer != null)
                {
                    this.microphoneCapturer.Stop();
                    this.microphoneCapturer.Dispose();
                    this.microphoneCapturer = null;
                }
    
                if (this.audioPlayer != null)
                {
                    this.audioPlayer.Dispose();
                    this.audioPlayer = null;
                }
            }
    
            private void button_stop_Click(object sender, EventArgs e)
            {
                if (this.audioPlayer == null)
                {
                    return;
                }
    
                if (this.microphoneCapturer != null)
                {
                    this.microphoneCapturer.Stop();
                    this.microphoneCapturer.Dispose();
                    this.microphoneCapturer = null;
                }
    
                this.audioPlayer.Clear();
                this.audioPlayer.Dispose();
                this.audioPlayer = null;
    
                this.label_msg.Visible = false;
                this.button_wav.Enabled = true;
                this.button_mic.Enabled = true;
                this.button_stop.Enabled = false;
            }        
        }
    复制代码

      看看demo执行的效果图:

      

        麦克风採集与播放Demo源代码下载



  • 相关阅读:
    Hibernate之HQL查询
    Java设计模式----状态模式(State)
    Java设计模式----备忘录模式(Memento)
    Java设计模式----命令模式(Command)
    Java设计模式----责任链模式(Chain of Responsibility)
    Java基础小知识
    Hibernate检索策略
    Java设计模式----观察者模式(Observer)
    Google代码实验室
    Codeforces Round #257 (Div. 2) 前四题
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6757890.html
Copyright © 2011-2022 走看看