29

我的任务是构建一个 .NET 客户端应用程序来检测 WAV 文件中的静音。

这可以通过内置的 Windows API 实现吗?或者,有什么好的图书馆可以帮助解决这个问题吗?

4

8 回答 8

14

音频分析是一件困难的事情,需要大量复杂的数学运算(想想傅立叶变换)。你要问的问题是“什么是沉默”。如果您尝试编辑的音频是从模拟源捕获的,则可能没有任何静音......它们只会是软噪声区域(线路嗡嗡声、环境背景噪声等)。

综上所述,一种应该起作用的算法是确定最小音量(幅度)阈值和持续时间(例如,<10dbA 超过 2 秒),然后简单地对波形进行音量分析,寻找符合此标准的区域(也许有一些过滤器用于毫秒尖峰)。我从来没有用 C# 写过这个,但是这篇CodeProject 文章看起来很有趣;它描述了用于绘制波形的 C# 代码……这与可用于进行其他幅度分析的代码相同。

于 2008-08-21T05:30:09.740 回答
10

http://www.codeproject.com/Articles/19590/WAVE-File-Processor-in-C

这具有去除静音和混合波形文件所需的所有代码。

享受。

于 2008-08-21T05:01:31.963 回答
10

如果您想有效地计算滑动窗口上的平均功率:对每个样本进行平方,然后将其添加到运行总数中。从之前的 N 个样本中减去平方值。然后进行下一步。这是CIC过滤器的最简单形式。Parseval 定理告诉我们,这种功率计算适用于时域和频域。

此外,您可能希望向系统添加滞后,以避免在功率水平在阈值水平附近波动时快速打开和关闭。

于 2008-08-28T03:21:26.513 回答
7

我正在使用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);
}

参考:

于 2017-09-03T14:23:18.330 回答
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;
            }
        }
于 2020-02-17T12:50:05.330 回答
1

我认为您不会找到任何用于检测静音的内置 API。但是您始终可以使用良好的数学/离散信号处理来找出响度。这是一个小例子:http: //msdn.microsoft.com/en-us/magazine/cc163341.aspx

于 2008-08-21T05:07:14.337 回答
1

使用Sox。它可以删除前导和尾随的静音,但您必须将其作为应用程序中的 exe 调用。

于 2009-10-22T12:55:43.470 回答
-2

请参阅下面的代码,使用 C# 检测 WAV 文件中的音频静音

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();
}
于 2014-02-01T16:10:11.357 回答