NAudio 峰值音量计
Posted
技术标签:
【中文标题】NAudio 峰值音量计【英文标题】:NAudio Peak Volume Meter 【发布时间】:2013-01-16 03:10:50 【问题描述】:我正在尝试使用 NAudio 编写峰值音量计。我的代码与http://channel9.msdn.com/coding4fun/articles/NET-Voice-Recorder 非常相似,但我的代码和链接的 Voice Recorder 项目都存在问题。
当播放恒定频率和音量的声音时,音量表最初以合理的电平开始,但随后衰减到非常小的值。我不确定为什么会这样,因为 NAudioDemo 中的峰值音量计不这样做。我试图在我的程序中复制来自 NAudioDemo 的代码,但我无法找到包含峰值音量计代码的代码文件。
谁能指导我使用另一种创建峰值音量计的解决方案或帮助我确定为什么我的解决方案(以及链接中提供的解决方案)都不起作用?
public MainWindow()
int waveInDevices = WaveIn.DeviceCount;
for (int waveInDevice = 0; waveInDevice < waveInDevices; waveInDevice++)
WaveInCapabilities deviceInfo = WaveIn.GetCapabilities(waveInDevice);
Console.WriteLine("Device 0: 1, 2 channels",
waveInDevice, deviceInfo.ProductName, deviceInfo.Channels);
WaveIn waveIn = new WaveIn();
waveIn.DeviceNumber = 0; //TODO: Let the user choose which device, this comes from the device numbers above
waveIn.DataAvailable += waveIn_DataAvailable;
int sampleRate = SAMPLE_RATE; // 8 kHz
int channels = 1; // mono
waveIn.WaveFormat = new WaveFormat(sampleRate, channels);
waveIn.StartRecording();
void waveIn_DataAvailable(object sender, WaveInEventArgs e)
for (int index = 0; index < e.BytesRecorded; index += 2)
short sample = (short)((e.Buffer[index + 1] << 8) |
e.Buffer[index + 0]);
float sample32 = sample / 32768f;
ProcessSample(sample32);
void ProcessSample(float sample1)
samplenumber += 1;
if (sample1 > maxval)
maxval = sample1;
if (sample1 < minval)
minval = sample1;
//Run updateView every few loops
if (samplenumber > (double)SAMPLE_RATE / DISPLAY_UPDATE_RATE)
samplenumber = 0;
updateView(); //needs to be fast!
void updateView()
Console.WriteLine(maxval);
Console.WriteLine(minval);
progressBar1.Value = (maxval - minval)*50;
maxval = 0;
minval = 0;
【问题讨论】:
我还没有检查过那个项目,但它可能不是真正的峰值计。有几种类似“VU”的算法。 什么是类似“VU”的算法? 一个 VU 表 (transitchicago.com/farechanges) 测量信号电平。指针跟踪水平的方式不是瞬时的......它有点落后,并且平均了一些高峰和低谷。有一些算法试图模仿这种行为。还有其他用于测量信号的算法。峰值计总是向您显示该组样本的***别。您链接到的项目可能使用某种 delta 算法,这就是为什么它在没有任何变化时下降的原因。这只是一个猜测,我没有看过代码。 @Brad 对不起,芝加哥交通票价变更页面的链接与 VU 计价器有何关联? ;) @JPollack,哈,抱歉,我一定是粘贴了链接而不复制。我不记得我要链接到什么...也许这个? en.wikipedia.org/wiki/File:VU-meter-reponse-graph.svg 【参考方案1】:那篇文章中发生的所有事情都是它在一个小间隔(例如 20 毫秒)内找到最大音频峰值,然后将其绘制在分贝标度上。要找到峰值,请检查区间中每个样本的值并选择最大值(这就是 SampleAggregator
类正在做的事情)。要转换为分贝,取最大值的以 10 为底的对数,然后乘以 10。所以 0dB 是最响亮的,低于 -96dB 的任何东西实际上都是静音。 (其实回头看这篇文章,我觉得我什至都懒得转换成分贝标度,我可能应该这样做)
【讨论】:
我明白了。那么为什么我会在几秒钟后看到“音量”下降呢?我正在努力解释这种奇怪的行为。 您确定要捕获音频吗?您是否尝试过记录几秒钟并查看值是否符合预期 我相信我正在捕捉音频,因为当我最初开始讲话时,音量会增加几秒钟。我用我的代码的适用部分更新了我的问题,如果这有帮助的话。 maxval 和 minval 的显示值从合理的水平开始,但几秒钟后迅速下降到接近零。 您将进度条设置为平均样本值,由于音频范围在 +/- 1 之间,因此自然会为 0。您需要在每个样本上使用 Math.Abs,只需找到最大的区间内的值。 我似乎找到了问题所在。当我选中录制设备属性框中的“禁用系统效果”框时,应用程序运行正常。非常感谢您的帮助!【参考方案2】:这是我从输出设备获得峰值的小解决方案。我正在使用 NAudio 版本 1.7.0.15
public partial class Form1 : Form
public Form1()
InitializeComponent();
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
var devices = enumerator.EnumerateAudioEndPoints(DataFlow.All, DeviceState.Active);
comboboxDevices.Items.AddRange(devices.ToArray());
private void timer1_Tick(object sender, EventArgs e)
if (comboboxDevices.SelectedItem != null)
var device = (MMDevice)comboboxDevices.SelectedItem;
progressBar1.Value = (int)(Math.Round(device.AudioMeterInformation.MasterPeakValue * 100));
【讨论】:
在打开声音设置之前它不起作用,有什么线索吗? 也意识到了这一点。您必须保持打开状态似乎很奇怪。大家有没有想办法不必这样做?【参考方案3】:尝试使用 MasterPeakValue 获取级别似乎比仅调用该方法更复杂,这违背了它的简单性。
我无意中意识到你必须打开设备进行记录,即使你不使用传入的数据。由于您正在启动 WaveIn,因此 MasterPeakValue 应该返回一个非 0 值。
一个简单的替代方法,仅用于测试,是打开系统录音设备的属性(右键单击系统音量图标并选择“录音设备”)。
(在 2 台不同的计算机上测试。)
【讨论】:
以上是关于NAudio 峰值音量计的主要内容,如果未能解决你的问题,请参考以下文章