博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分贝显示器,实时显示声音强度(附源码)
阅读量:5018 次
发布时间:2019-06-12

本文共 5742 字,大约阅读时间需要 19 分钟。

使用 一文中提到的技术,我们可以基本实现QQ的语音视频测试向导的功能了。但是,我觉得语音测试这块的体验还可以做得更好一点,就像QQ语音测试一样,实时显示麦克风采集到的声音的强度:

      

接下来,我们做个小demo,来实现类似的功能。先上demo运行起来的截图:

        

(界面确实比较丑,我们这里的重点在于技术方面如何实现,如果你愿意花点时间,可以将其美化得跟QQ的那个一样漂亮^_^)

 

1.实现思路

实现这个小例子的主要思路如下:

(1)使用采集和播放从麦克风的输入数据(PCM)。

(2)对采集到的数据进行傅立叶变换,变换的结果就可以反应声音的强度。

(3)使用ProgressBar控件来实时显示声音的强度信息。

2.具体实现

(1)傅立叶变换算法 

public static class FourierTransformer    {        public static double[] FFTDb(double[] source)        {                      int sourceLen = source.Length;            int nu = (int)(Math.Log(sourceLen) / Math.Log(2));            int halfSourceLen = sourceLen / 2;            int nu1 = nu - 1;            double[] xre = new double[sourceLen];            double[] xim = new double[sourceLen];            double[] decibel = new double[halfSourceLen];            double tr, ti, p, arg, c, s;            for (int i = 0; i < sourceLen; i++)            {                xre[i] = source[i];                xim[i] = 0.0f;            }            int k = 0;            for (int l = 1; l <= nu; l++)            {                while (k < sourceLen)                {                    for (int i = 1; i <= halfSourceLen; i++)                    {                        p = BitReverse(k >> nu1, nu);                        arg = 2 * (double)Math.PI * p / sourceLen;                        c = (double)Math.Cos(arg);                        s = (double)Math.Sin(arg);                        tr = xre[k + halfSourceLen] * c + xim[k + halfSourceLen] * s;                        ti = xim[k + halfSourceLen] * c - xre[k + halfSourceLen] * s;                        xre[k + halfSourceLen] = xre[k] - tr;                        xim[k + halfSourceLen] = xim[k] - ti;                        xre[k] += tr;                        xim[k] += ti;                        k++;                    }                    k += halfSourceLen;                }                k = 0;                nu1--;                halfSourceLen = halfSourceLen / 2;            }            k = 0;            int r;            while (k < sourceLen)            {                r = BitReverse(k, nu);                if (r > k)                {                    tr = xre[k];                    ti = xim[k];                    xre[k] = xre[r];                    xim[k] = xim[r];                    xre[r] = tr;                    xim[r] = ti;                }                k++;            }            for (int i = 0; i < sourceLen / 2; i++)            {                decibel[i] = 10.0 * Math.Log10((float)(Math.Sqrt((xre[i] * xre[i]) + (xim[i] * xim[i]))));            }            return decibel;        }        private static int BitReverse(int j, int nu)        {            int j2;            int j1 = j;            int k = 0;            for (int i = 1; i <= nu; i++)            {                j2 = j1 / 2;                k = 2 * k + j1 - 2 * j2;                j1 = j2;            }            return k;        }    }

 至于傅立叶变换与分贝有什么关系,网上有很多相关的资料,可以baidu一下。对有兴趣的童鞋,强烈推荐阅读这篇文章 -- 。

(2)初始化OMCS服务器、设备管理器、麦克风设备 

//获取麦克风列表         IList
microphones = SoundDevice.GetMicrophones(); this.comboBox2.DataSource = microphones; if (microphones.Count > 0) { this.comboBox2.SelectedIndex = 0; } //初始化OMCS服务器 OMCSConfiguration configuration = new OMCSConfiguration(10, 1, EncodingQuality.High, 16000, 800, 600); this.multimediaServer = new MultimediaServer(9000, new DefaultUserVerifier(), configuration, false, null); this.multimediaManager.DeviceErrorOccurred += new CbGeneric
(multimediaManager_DeviceErrorOccurred); this.multimediaManager.AudioCaptured += new CbGeneric
(multimediaManager_AudioCaptured); this.microphoneConnector1.ConnectEnded += new CbGeneric
(microphoneConnector1_ConnectEnded);

(3)连接麦克风,开始采集

if (!SoundDevice.IsSoundCardInstalled())    {        this.label_error.Visible = true;        this.label_error.Text = "声卡没有安装";    }    //初始化多媒体管理器     this.multimediaManager.MicrophoneDeviceIndex = this.comboBox2.SelectedIndex;                      this.multimediaManager.Initialize("tester", "", "127.0.0.1", 9000); //与OMCS服务器建立连接,并登录    //尝试连接麦克风                  this.microphoneConnector1.BeginConnect("tester");

首先,初始化本地多媒体设备管理器,然后使用麦克风连接器连接到当前登录用户“tester”(即“自己”)麦克风设备。如果连接成功,多媒体管理器将会触发AudioCaptured事件,我们通过这个事件来截获音频数据。

(4)处理采集到的音频数据,并显示结果 

void multimediaManager_AudioCaptured(byte[] data)        {            double[] wave = new double[data.Length / 2];            int h = 0;            for (int i = 0; i < wave.Length; i += 2)            {                wave[h] = (double)BitConverter.ToInt16(data, i); //采样位数为16bit                ++h;            }            double[] res = FourierTransformer.FFTDb(wave);            double kk = 0;            foreach (double dd in res)            {                kk += dd;            }            if (kk < 0)            {                kk = 0;            }            this.showResult(kk / res.Length);        }                private void showResult(double rs)        {            if (this.InvokeRequired)            {                this.BeginInvoke(new CbGeneric
(this.showResult), rs); } else { int rss = (int)(rs * 2); if (rss < 40) { rss = 40; } if (rss > 100) { rss = 100; } this.progressBar1.Value = rss; } }

注意:由于OMCS音频采样的位数为16bit,这样,一个单位的语音样本的字节数为2个字节。所以,傅立叶变换前,先要将原始的PCM数据(byte[])转为Int16的数组。

在显示分贝强度时,我偷了下懒,直接使用了ProgressBar控件,体验不是很好,勉强能表达出意思吧。

3.Demo程序

    

 

转载于:https://www.cnblogs.com/zhuweisky/p/3269896.html

你可能感兴趣的文章
kafka安装
查看>>
mui.toast样式风格及位置修改教程
查看>>
Android中的控件
查看>>
数据库的锁
查看>>
C++学习4 类
查看>>
[hihocoder 1050]求树的最长链
查看>>
USACO 4.1 Fence Rails
查看>>
【校招面试 之 C/C++】第3题 为什么要内存对齐?以及内存对齐的方式
查看>>
【校招面试 之 C/C++】第22题 C++ STL(四)之List
查看>>
Caused by: java.lang.ClassNotFoundException: org.apache.commons.io.FileUtils
查看>>
android关于实现滑动界面
查看>>
《Intel汇编第5版》 汇编调用子过程
查看>>
使用Highcharts结合PHP与Mysql生成饼状图
查看>>
python中multiprocessing模块
查看>>
图像切割之(一)概述
查看>>
JAVA修饰符类型(public,protected,private,friendly)
查看>>
flex利用webservice上传照片
查看>>
IOS开发之Bug--使用KVC的易错情况
查看>>
python list和tuple
查看>>
Python开发环境搭建(python+EditPlus)
查看>>