65.9K
CodeProject 正在变化。 阅读更多。
Home

对数声强计

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.80/5 (5投票s)

2010年7月16日

CPOL

2分钟阅读

viewsIcon

81816

downloadIcon

8662

一个简单的立体声音量计,带有音频捕获卡选择功能。

VUMeter.jpg

引言

这是一个简单的对数立体声峰值音量计。测量单位为分贝 (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。
© . All rights reserved.