0 Comments

I’m hoping to write a few brief code snippets to demonstrate various uses of NAudio, to eventually form the basis of an FAQ. This example shows how you can take a WAV file and trim a section out of it. You specify the TimeSpan to remove from the beginning and end, as well as an output WAV file. Please note this will only be reliable with PCM format WAV files.

public static class WavFileUtils
{
    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);
                }
            }
        }
    }
}
Want to get up to speed with the the fundamentals principles of digital audio and how to got about writing audio applications with NAudio? Be sure to check out my Pluralsight courses, Digital Audio Fundamentals, and Audio Programming with NAudio.
Vote on HN

Comments

Comment by Frederic

Hello,

Was pleased with this example.
Tried it out with NAudio 1.3 (which was totally new to me) and worked perfectly on regular wav disk files.

My scenario involed in-memory Waves so I was pleased to see that (apparently starting with 1.3 release) WaveFileReader/Writer did support Streams.

Problem is that in the current WaveFileWriter class design, wave header and length is only updated when the object is disposed... which is ok when writing to a file, a little bit less when the stream is from another kind, because we might want to copy the result stream somewhere before disposing it.

Correct me if I'm wrong, but I was thinking of copying the block of code that updates the header from the Dispose method into the Flush method. Do you think that could do the job without breaking anything else?

UPDATE: Actually I did try this quick fix and it dit it, at least to me. Keep on the good work on this very helpful library.

Regards
Frederic

Comment by Anonymous

Can we use NAudio for web application..?

Anonymous
Comment by Mark H

the web server can use NAudio to manipulate audio files, but NAudio cannot be used on the client side in the browser

Comment by StarTraX

I have tried to implement this code in Visual Basic, but am getting an error
"Must read complete blocks" at
Dim bytesRead As Integer = reader.Read(buffer, 0, bytesToRead)
when invoking as follows:

Sub TrimWavFile(ByVal inPath As String, ByVal outPath As String, _
ByVal cutFromStart As TimeSpan, ByVal cutFromEnd As TimeSpan)
Dim reader As WaveFileReader = New WaveFileReader(inPath)
Dim writer As WaveFileWriter = New WaveFileWriter(outPath)
Dim bytesPerMillisecond As Integer = reader.WaveFormat.AverageBytesPerSecond / 1000
Dim startPos As Integer = cutFromStart.TotalMilliseconds * bytesPerMillisecond
startPos = startPos - startPos Mod reader.WaveFormat.BlockAlign
Dim endBytes As Integer = cutFromEnd.TotalMilliseconds * bytesPerMillisecond
endBytes = endBytes - endBytes Mod reader.WaveFormat.BlockAlign
Dim endPos As Integer = reader.Length - endBytes
TrimWavFile(reader, writer, startPos, endPos)
End Sub

Sub TrimWavFile(ByVal reader As WaveFileReader, ByVal writer As WaveFileWriter, ByVal startPos As Integer, ByVal endPos As Integer)
reader.Position = startPos
Dim buffer(1024) As Byte
While reader.Position < endPos
Dim bytesRequired As Integer = endPos - reader.Position
If bytesRequired > 0 Then
Dim bytesToRead As Integer = Math.Min(bytesRequired, buffer.Length)
Dim bytesRead As Integer = reader.Read(buffer, 0, bytesToRead)
If (bytesRead > 0) Then
writer.WriteData(buffer, 0, bytesRead)
End If
End If
End While
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
TrimWavFile("F:\VBProjectsDevelopment\3DTrackDisplay1\Sounds\tonovario.wav", _
"F:\VBProjectsDevelopment\3DTrackDisplay1\Sounds\tonovarioShort.wav", _
New TimeSpan(10000000), New TimeSpan(10000000))

End Sub

My C# coding level is about 3 out of 10 so maybe I've missed something in the migration.

Comment by Mark H

what is the value of bytesToRead?

Comment by sodaDreamer

Thanks for the snippet. This worked a treat for me!

I did spot one issue though - there's a rounding error when calculating bytesPerMillisecond. If you change it from an int to a double that should sort it.

Also, for what it's worth the 'Must read complete blocks' error is because the data must be read in multiples of reader.WaveFormat.BlockAlign. I had this issue reading a GSM file with a block align of 65, so I set the buffer size to BlockAlign * 100.

sodaDreamer
Comment by RelevantAds

Getting the "Must read complete blocks" error. Is this due to selecting a bad TimeSpan; or an oddly formed WAV file. My is 13kbps bitrate. I have 63 bytes left.

Comment by Mark H

instead of a buffer size of 1024, make sure it is sized to a multiple of your WaveFormat.BlockAlign.

comments powered by Disqus