对数声强计






4.80/5 (5投票s)
一个简单的立体声音量计,带有音频捕获卡选择功能。
引言
这是一个简单的对数立体声峰值音量计。测量单位为分贝 (dB)。它在声音录制或混音应用中会很有用。
背景
这是另一个项目的组成部分,我正在尝试创建一个莫尔斯电码控制面板,通过声卡发送和接收。我最初使用了 Jacob Klint 的 VolumeMeter (Managed DirectX),但发现它崩溃了,并且无法为我的应用程序足够快地跟踪峰值声音。莫尔斯电码是以毫秒为单位测量的。
我重用了 Jacob 的一些代码来进行音频捕获。
先决条件
可能需要先安装 DirectX 9.0 SDK。
Using the Code
在表单加载时,音频捕获设备将列入组合框,并选择列表中的第一个设备。音频缓冲区读取和进度条更新将自动使用线程例程启动。
可以通过更改 FrameDelay
值来调整仪表响应。10 到 30 之间的值可以得到一个好的结果。
声音捕获是两个通道的 16 位样本,提供 +/-32768 的值。每次采集八个样本。Jacob 在这里描述了采集代码:https://codeproject.org.cn/KB/directx/volumemeter.aspx。
我使用线程在后台读取捕获缓冲区并更新进度条。
要将值转换为 dB,请使用音量 (dB) = 20*(log10 (平均样本 / 32768))。平均样本必须是 RMS(均方根)值,并将产生 0 到 -90dB 之间的值。由于进度条仅接受正值,因此添加了 100 的偏移量。通过将进度条值限制为 74-100,仅查看最高的 26dB。
// Imports required
Imports Microsoft.DirectX.DirectSound
Imports System.Threading
Imports System.Collections.Specialized
// Detecting the Sound Cards
Private Sub VU_Sound_Form_Load(ByVal sender As Object,_
ByVal e As System.EventArgs) Handles Me.Load
Dim audioDevices As New CaptureDevicesCollection
Dim x As Integer = 0
While x < audioDevices.Count
ComboBox1.Items.Add(audioDevices.Item(x).Description)
x = x + 1
End While
ComboBox1.SelectedIndex = 0
Start()
End Sub
// Reading the capture buffer and convert to decibels
Dim samples__1 As Array = buffer.Read(0, GetType(Int16), _
LockFlag.FromWriteCursor, SAMPLE_FORMAT_ARRAY)
Dim leftGoal As Integer = 0
Dim rightGoal As Integer = 0
// Convert the 8 samples to positive values and sum them togather
For i As Integer = 0 To SAMPLES - 1
If CType(samples__1.GetValue(i, 0, 0), Int16) < 0 Then
leftGoal -= CType(samples__1.GetValue(i, 0, 0), Int16)
Else
leftGoal += CType(samples__1.GetValue(i, 0, 0), Int16)
End If
If CType(samples__1.GetValue(i, 1, 0), Int16) < 0 Then
rightGoal -= CType(samples__1.GetValue(i, 1, 0), Int16)
Else
rightGoal += CType(samples__1.GetValue(i, 1, 0), Int16)
End If
Next
//Calculate the average of the 8 samples
leftGoal = CInt(Math.Abs(leftGoal \ SAMPLES))
rightGoal = CInt(Math.Abs(rightGoal \ SAMPLES))
//Convert values to deecibels
If leftGoal = 0 Then leftGoal = 1
If rightGoal = 0 Then rightGoal = 1
leftGoal = (100 + (20 * Math.Log10(leftGoal / 32768)))
rightGoal = (100 + (20 * Math.Log10(rightGoal / 32768)))
// Updating the progress bars so
// If the measured value is larger than the
// progress bar value then it is the peak
If ProgressBar2.Value < rightGoal Then
ProgressBar2.Value = rightGoal
End If
// If the measured value is smaller than the progress bar value
// step reduce the bar
If ProgressBar2.Value > rightGoal Then ' decrement the value
If absStepSize2 < Math.Abs(rightGoal - ProgressBar2.Value) Then
exactValue2 += stepSize2
ProgressBar2.Value = Math.Truncate(exactValue2)
Else
ProgressBar2.Value = rightGoal
End If
End If
Thread.Sleep(m_frameDelay)
关注点
这是我第一次使用线程。我发现,如果您在启动线程之前没有添加行 Control.CheckForIllegalCrossThreadCalls = False
,则表单将不会更新。
历史
- 版本 1.0。