Search code examples
c#.netaudionaudio

Splitting a Wav File using NAudio removes 1 second from each part


I am using NAudio to split a Wav File into multiple parts of equal intervals. I am using a version of the code available on Sound Code by Mark Heath:

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;
            float bytesPerMillisecond = reader.WaveFormat.AverageBytesPerSecond / 1000f;
            int startPos = (int)cutFromStart.TotalMilliseconds * (int)bytesPerMillisecond;
            startPos = startPos - startPos % reader.WaveFormat.BlockAlign;

            int endBytes = (int)cutFromEnd.TotalMilliseconds * (int)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[reader.WaveFormat.BlockAlign * 100];
    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);
            }
        }
    }
}

This is splitting the Wav file, but each part is 1 second shorter than the interval specified. I dont know if this is an issue with the code or the library itself. Has anyone faced the same issue? If so, was anyone able to solve it?

Edit This is what I'm sending to the function:

TimeSpan cutFromStart = new TimeSpan(0, 0, 0);
TimeSpan cutFromEnd = new TimeSpan(0, 0, 0);
cutFromEnd = totalTime.Subtract(interval);

for (i = 0; i < numberOfParts; i++)
{
    outPath = inpath + prefix + (i + 1).ToString() + ".wav";
    TrimWavFile(inPath, outPath, cutFromStart, cutFromEnd);
    cutFromStart = cutFromStart.Add(interval);
    cutFromEnd = cutFromEnd.Subtract(interval);
}

Solution

  • I suspect there is a bug in your position calculation.

    But maybe you will find it easier to use this technique

    using (var reader = new AudioFileReader(inPath))
    {
        reader.CurrentTime = startTime; // jump forward to the position we want to start from
        WaveFileWriter.CreateWaveFile16(outPath, reader.Take(duration));
    }