我的任务是构建一个.NET客户端应用程序来检测WAV文件中的静音。
内置Windows API是否可以实现?或者,还有任何好的图书馆来帮助解决这个问题吗?
答案 0 :(得分:14)
音频分析是一项困难的事情,需要大量复杂的数学运算(想想傅立叶变换)。你要问的问题是“什么是沉默”。如果您尝试编辑的音频是从模拟信号源捕获的,则可能没有任何静音......它们只会是软噪声区域(线路嗡嗡声,环境背景噪声等)。
所有这一切,应该工作的算法将是确定最小音量(幅度)阈值和持续时间(例如,<10dbA超过2秒),然后简单地对波形进行体积分析以寻找区域符合此标准(可能有一些过滤器用于毫秒峰值)。我从未在C#中写过这个,但这个CodeProject article看起来很有趣;它描述了用于绘制波形的C#代码......这是可用于进行其他振幅分析的相同类型的代码。
答案 1 :(得分:10)
答案 2 :(得分:9)
如果要有效计算滑动窗口的平均功率:对每个样本求平方,然后将其添加到运行总计中。从之前的N个样本中减去平方值。然后转到下一步。这是CIC过滤器的最简单形式。 Parseval's Theorem告诉我们,此功率计算适用于时域和频域。
此外,您可能需要将Hysteresis添加到系统中,以避免在功率水平高于阈值水平时快速打开和关闭。
答案 3 :(得分:4)
这是一个很好的变体,可以检测阈值交替:
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;
}
}
答案 4 :(得分:2)
我使用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);
}
<强>参考文献:强>
答案 5 :(得分:1)
我认为你找不到任何用于检测沉默的内置API。但是你总是可以使用好的数学/ discreete信号处理来找出响度。 这是一个小例子:http://msdn.microsoft.com/en-us/magazine/cc163341.aspx
答案 6 :(得分:1)
使用Sox。它可以删除前导和尾随的静音,但您必须将其称为应用程序中的exe。
答案 7 :(得分:-3)
请参阅以下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();
}