【问题标题】:Detecting audio silence in WAV files using C#使用 C# 检测 WAV 文件中的音频静音
【发布时间】:2010-09-06 08:51:48
【问题描述】:

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

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

【问题讨论】:

    标签: c# .net audio


    【解决方案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);
          }
          

          参考资料:

          【讨论】:

          • db 公式中的amplitude 是什么?我正在努力从录制的音频中检测和删除静音大约 1.5 个月,但我还没有成功......这些是我在堆栈中关于这个主题的问题,Question 1Question 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 或未来的访问者可能需要这些品质。你应该批评答案与问题相关,而不是你的意识形态。
            • 我敢肯定,如果帖子中包含关于使用第三方非免费库的提醒,它就不会被否决,而不是随便偷偷插入这样的广告。
            猜你喜欢
            • 1970-01-01
            • 2018-01-13
            • 1970-01-01
            • 1970-01-01
            • 2013-05-30
            • 1970-01-01
            • 1970-01-01
            • 2014-10-31
            • 1970-01-01
            相关资源
            最近更新 更多