【问题标题】:Trim a wav file修剪 wav 文件
【发布时间】:2024-04-22 12:20:02
【问题描述】:

我正在尝试使用来自here 的代码修剪文件

 public static void TrimWavFile(string inPath, string outPath, TimeSpan cutFromStart, TimeSpan cutFromEnd)
 {
    using (WaveFileReader reader = new WaveFileReader(inPath))
    {
        using (WaveFileWriter writer = new WaveFileWriter(outPath, reader.WaveFormat))
        {
            int bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000;

            int startPos = (int)cutFromStart.TotalMilliseconds * bytesPerMillisecond;
            startPos = startPos - startPos % reader.WaveFormat.BlockAlign;

            int endBytes = (int)cutFromEnd.TotalMilliseconds * bytesPerMillisecond;
            endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
            int endPos = (int)reader.Length - endBytes; 

            TrimWavFile(reader, writer, startPos, endPos);
        }
    }
}

private static void TrimWavFile(WaveFileReader reader, WaveFileWriter writer, int startPos, int endPos)
{
    reader.Position = startPos;
    byte[] buffer = new byte[1024];
    while (reader.Position < endPos)
    {
        int bytesRequired = (int)(endPos - reader.Position);
        if (bytesRequired > 0)
        {
            int bytesToRead = Math.Min(bytesRequired, buffer.Length);
            int bytesRead = reader.Read(buffer, 0, bytesToRead);
            if (bytesRead > 0)
            {
                writer.WriteData(buffer, 0, bytesRead);
            }
        }
    }
}

我在那里准确地写了什么,但是当我打开文件时我修剪它说他已经损坏了。

这段代码是如何工作的? while (reader.Position &lt; endPos) 始终为真,reader.Position 不会改变。

编辑 1 else if() 与 else 相同,但我只是为了确定。

while (reader.Position < end)
        {
            int bytesRequired = (int)(end - reader.Position);
            if (bytesRequired > 0)
            {
                int bytesToRead = Math.Min(bytesRequired, buffer.Length);
                int bytesRead = reader.Read(buffer, 0, bytesToRead);
                if (bytesRead > 0)
                {
                    writer.Write(buffer, 0, bytesRead);
                }
                else if (bytesRead == 0)
                {
                   break;
                }
            }
            else if (bytesRequired <= 0)
            {
                break;
            }
        }

【问题讨论】:

    标签: c# wpf audio trim naudio


    【解决方案1】:

    如果出现bytesRequired &lt;= 0bytesRead == 0,则应该跳出while 循环

    【讨论】:

    • 我做到了,但我仍然得到这个:i.stack.imgur.com/wDT0S.png你知道为什么吗?
    • 输入文件可以播放吗?什么是波形?
    • 输入是可播放的,它是一个wav文件。
    • 我调试了程序,它甚至没有进入 else 并打破了 while 循环。我在问题中添加了代码。
    【解决方案2】:

    我找到了解决方案。 writer.Dispose() 完成后我不得不写它。 像这样:

    public static void TrimWavFile(string inPath, string outPath, TimeSpan cutFromStart, TimeSpan cutFromEnd)
     {
        using (WaveFileReader reader = new WaveFileReader(inPath))
        {
            using (WaveFileWriter writer = new WaveFileWriter(outPath, reader.WaveFormat))
            {
                int bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000;
    
                int startPos = (int)cutFromStart.TotalMilliseconds * bytesPerMillisecond;
                startPos = startPos - startPos % reader.WaveFormat.BlockAlign;
    
                int endBytes = (int)cutFromEnd.TotalMilliseconds * bytesPerMillisecond;
                endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
                int endPos = (int)reader.Length - endBytes; 
    
                TrimWavFile(reader, writer, startPos, endPos);
                writer.Dispose();
            }
        }
    

    【讨论】:

    • 奇怪——这就是 using 语句应该为你做的事情
    【解决方案3】:

    您使用的示例代码有点过时并且有一些错误。 这是一个更新版本(对我来说非常好用):

    private void Cut()
    {
      var filename = @"G:\Voice\Samples\LongAudioFile.wav";
      FileInfo fi = new FileInfo(filename);
      var outputPath = System.IO.Path.Combine(fi.Directory.FullName, string.Format("{0}_Shorter{1}", fi.Name.Replace(fi.Extension, ""), fi.Extension));
    
      TrimWavFile(filename, outputPath, TimeSpan.FromHours(1));
    }
    
    public static void TrimWavFile(string inPath, string outPath, TimeSpan duration)
    {
      using (WaveFileReader reader = new WaveFileReader(inPath))
      {
        using (WaveFileWriter writer = new WaveFileWriter(outPath, reader.WaveFormat))
        {
          float bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000f;
    
          int startPos = 0;
          startPos = startPos - startPos % reader.WaveFormat.BlockAlign;
    
          int endBytes = (int)Math.Round(duration.TotalMilliseconds * bytesPerMillisecond);
          endBytes = endBytes - endBytes % reader.WaveFormat.BlockAlign;
          int endPos = endBytes;
    
          TrimWavFile(reader, writer, startPos, endBytes);
        }
      }
    }
    
    private static void TrimWavFile(WaveFileReader reader, WaveFileWriter writer, int startPos, int endPos)
    {
      reader.Position = startPos;
      byte[] buffer = new byte[reader.BlockAlign * 1024];
      while (reader.Position < endPos)
      {
        int bytesRequired = (int)(endPos - reader.Position);
        if (bytesRequired > 0)
        {
          int bytesToRead = Math.Min(bytesRequired, buffer.Length);
          int bytesRead = reader.Read(buffer, 0, bytesToRead);
          if (bytesRead > 0)
          {
            writer.Write(buffer, 0, bytesRead);
          }
        }
      }
    }
    

    请注意,在我的情况下,我需要从开始到某个点(例如:1H)获取音频。 如果您想在中间的某个地方获得特定部分,只需更改:

    int startPos = 0;
    

    int startBytes = (int)Math.Round(startPoint.TotalMilliseconds * bytesPerMillisecond);
    startBytes = startBytes - startBytes % reader.WaveFormat.BlockAlign;
    int startPos = startBytes;
    

    【讨论】: