使用 C# 检测 WAV 文件中的音频静音
Posted
技术标签:
【中文标题】使用 C# 检测 WAV 文件中的音频静音【英文标题】:Detecting audio silence in WAV files using C# 【发布时间】:2010-09-06 08:51:48 【问题描述】:我的任务是构建一个 .NET 客户端应用程序来检测 WAV 文件中的静音。
这可以通过内置的 Windows API 实现吗?或者,有什么好的图书馆可以帮助解决这个问题吗?
【问题讨论】:
【参考方案1】:音频分析是一件困难的事情,需要大量复杂的数学运算(想想傅立叶变换)。你要问的问题是“什么是沉默”。如果您尝试编辑的音频是从模拟源捕获的,则可能没有任何静音......它们只会是软噪声区域(线路嗡嗡声、环境背景噪声等)。
总而言之,一种应该起作用的算法是确定最小音量(幅度)阈值和持续时间(例如,CodeProject article 看起来很有趣;它描述了用于绘制波形的 C# 代码......这与可用于进行其他幅度分析的代码相同。
【讨论】:
【参考方案2】:如果您想有效地计算滑动窗口的平均功率:对每个样本进行平方,然后将其添加到运行总计中。从之前的 N 个样本中减去平方值。然后进行下一步。这是CIC 过滤器的最简单形式。 Parseval's Theorem 告诉我们,这种功率计算适用于时域和频域。
此外,您可能希望将Hysteresis 添加到系统中,以避免在功率水平接近阈值水平时快速打开和关闭。
【讨论】:
【参考方案3】:http://www.codeproject.com/Articles/19590/WAVE-File-Processor-in-C
这包含去除静音和混合波形文件所需的所有代码。
享受吧。
【讨论】:
【参考方案4】:我正在使用NAudio,我想检测音频文件中的静音,以便报告或截断。
经过大量研究,我想出了这个基本的实现。因此,我为 AudioFileReader
类编写了一个扩展方法,它返回文件开头/结尾处或从特定位置开始的静音持续时间。
这里:
static class AudioFileReaderExt
public enum SilenceLocation Start, End
private static bool IsSilence(float amplitude, sbyte threshold)
double dB = 20 * Math.Log10(Math.Abs(amplitude));
return dB < threshold;
public static TimeSpan GetSilenceDuration(this AudioFileReader reader,
SilenceLocation location,
sbyte silenceThreshold = -40)
int counter = 0;
bool volumeFound = false;
bool eof = false;
long oldPosition = reader.Position;
var buffer = new float[reader.WaveFormat.SampleRate * 4];
while (!volumeFound && !eof)
int samplesRead = reader.Read(buffer, 0, buffer.Length);
if (samplesRead == 0)
eof = true;
for (int n = 0; n < samplesRead; n++)
if (IsSilence(buffer[n], silenceThreshold))
counter++;
else
if (location == SilenceLocation.Start)
volumeFound = true;
break;
else if (location == SilenceLocation.End)
counter = 0;
// reset position
reader.Position = oldPosition;
double silenceSamples = (double)counter / reader.WaveFormat.Channels;
double silenceDuration = (silenceSamples / reader.WaveFormat.SampleRate) * 1000;
return TimeSpan.FromMilliseconds(silenceDuration);
这将接受几乎任何音频文件格式不仅仅是 WAV。
用法:
using (AudioFileReader reader = new AudioFileReader(filePath))
TimeSpan duration = reader.GetSilenceDuration(AudioFileReaderExt.SilenceLocation.Start);
Console.WriteLine(duration.TotalMilliseconds);
参考资料:
How audio dB levels are calculated. Floating-point samples range。 More about amplitude。【讨论】:
db 公式中的amplitude
是什么?我正在努力从录制的音频中检测和删除静音大约 1.5 个月,但我还没有成功......这些是我在堆栈中关于这个主题的问题,Question 1 和 Question 2 我将不胜感激你帮我解决这个问题,我是一名学生,这是我的家庭作业,我不是这个学科的专业人士
当我在 mp4 视频上运行此代码时,值在 -96ish 到 0 之间。0 是最大音量【参考方案5】:
这是检测阈值交替的一个很好的变体:
static class AudioFileReaderExt
private static bool IsSilence(float amplitude, sbyte threshold)
double dB = 20 * Math.Log10(Math.Abs(amplitude));
return dB < threshold;
private static bool IsBeep(float amplitude, sbyte threshold)
double dB = 20 * Math.Log10(Math.Abs(amplitude));
return dB > threshold;
public static double GetBeepDuration(this AudioFileReader reader,
double StartPosition, sbyte silenceThreshold = -40)
int counter = 0;
bool eof = false;
int initial = (int)(StartPosition * reader.WaveFormat.Channels * reader.WaveFormat.SampleRate / 1000);
if (initial > reader.Length) return -1;
reader.Position = initial;
var buffer = new float[reader.WaveFormat.SampleRate * 4];
while (!eof)
int samplesRead = reader.Read(buffer, 0, buffer.Length);
if (samplesRead == 0)
eof = true;
for (int n = initial; n < samplesRead; n++)
if (IsBeep(buffer[n], silenceThreshold))
counter++;
else
eof=true; break;
double silenceSamples = (double)counter / reader.WaveFormat.Channels;
double silenceDuration = (silenceSamples / reader.WaveFormat.SampleRate) * 1000;
return TimeSpan.FromMilliseconds(silenceDuration).TotalMilliseconds;
public static double GetSilenceDuration(this AudioFileReader reader,
double StartPosition, sbyte silenceThreshold = -40)
int counter = 0;
bool eof = false;
int initial = (int)(StartPosition * reader.WaveFormat.Channels * reader.WaveFormat.SampleRate / 1000);
if (initial > reader.Length) return -1;
reader.Position = initial;
var buffer = new float[reader.WaveFormat.SampleRate * 4];
while (!eof)
int samplesRead = reader.Read(buffer, 0, buffer.Length);
if (samplesRead == 0)
eof=true;
for (int n = initial; n < samplesRead; n++)
if (IsSilence(buffer[n], silenceThreshold))
counter++;
else
eof=true; break;
double silenceSamples = (double)counter / reader.WaveFormat.Channels;
double silenceDuration = (silenceSamples / reader.WaveFormat.SampleRate) * 1000;
return TimeSpan.FromMilliseconds(silenceDuration).TotalMilliseconds;
主要用途:
using (AudioFileReader reader = new AudioFileReader("test.wav"))
double duratioff = 1;
double duration = 1;
double position = 1;
while (duratioff >-1 && duration >-1)
duration = reader.GetBeepDuration(position);
Console.WriteLine(duration);
position = position + duration;
duratioff = reader.GetSilenceDuration(position);
Console.WriteLine(-duratioff);
position = position + duratioff;
【讨论】:
【参考方案6】:我认为您不会找到任何用于检测静音的内置 API。但是您始终可以使用良好的数学/离散信号处理来找出响度。 这是一个小例子:http://msdn.microsoft.com/en-us/magazine/cc163341.aspx
【讨论】:
此链接已损坏...:(【参考方案7】:使用Sox。它可以删除前导和尾随的静音,但您必须将其作为应用程序中的 exe 调用。
【讨论】:
调用外部进程有时看起来很淘气。但更重要的是使用最好的工具。【参考方案8】:查看下面来自Detecting audio silence in WAV files using C#的代码
private static void SkipSilent(string fileName, short silentLevel)
WaveReader wr = new WaveReader(File.OpenRead(fileName));
IntPtr format = wr.ReadFormat();
WaveWriter ww = new WaveWriter(File.Create(fileName + ".wav"),
AudioCompressionManager.FormatBytes(format));
int i = 0;
while (true)
byte[] data = wr.ReadData(i, 1);
if (data.Length == 0)
break;
if (!AudioCompressionManager.CheckSilent(format, data, silentLevel))
ww.WriteData(data);
ww.Close();
wr.Close();
【讨论】:
上面的代码需要第三方库(Alvas Audio),这并不便宜。 貌似非开源Alvas Audio
库的广告。
我不确定为什么商业解决方案被低估为答案。有没有这样的政策?该软件可能有很多其他人无法实现的品质,而 OP 或未来的访问者可能需要这些品质。你应该批评答案与问题相关,而不是你的意识形态。
我敢肯定,如果帖子中包含关于使用第三方非免费库的提醒,它就不会被否决,而不是随便偷偷插入这样的广告。以上是关于使用 C# 检测 WAV 文件中的音频静音的主要内容,如果未能解决你的问题,请参考以下文章