Sergey Malyutin
Sergey Malyutin

Reputation: 1554

Convert a wav file to 8000Hz 16Bit Mono Wav

I need to convert a wav file to 8000Hz 16Bit Mono Wav. I already have a code, which works well with NAudio library, but I want to use MemoryStream instead of temporary file.

using System.IO;
using NAudio.Wave;

    static void Main()
    {
        var input = File.ReadAllBytes("C:/input.wav");
        var output = ConvertWavTo8000Hz16BitMonoWav(input);
        File.WriteAllBytes("C:/output.wav", output);
    }

    public static byte[] ConvertWavTo8000Hz16BitMonoWav(byte[] inArray)
    {
        using (var mem = new MemoryStream(inArray))
        using (var reader = new WaveFileReader(mem))
        using (var converter = WaveFormatConversionStream.CreatePcmStream(reader))
        using (var upsampler = new WaveFormatConversionStream(new WaveFormat(8000, 16, 1), converter))
        {
            // todo: without saving to file using MemoryStream or similar
            WaveFileWriter.CreateWaveFile("C:/tmp_pcm_8000_16_mono.wav", upsampler);
            return File.ReadAllBytes("C:/tmp_pcm_8000_16_mono.wav");
        }
    }

Upvotes: 4

Views: 3757

Answers (3)

Max
Max

Reputation: 1069

This is what worked for me (in 2024), reading the docs from NAudio

public void ConvertWav(String waveFilePath, String toWaveFilePath)
{
    int outRate = 8000;
    using (var reader = new WaveFileReader(waveFilePath))
    {
        var outFormat = new WaveFormat(outRate, 16, 1);
        using (var resampler = new MediaFoundationResampler(reader, outFormat))
        {               
            WaveFileWriter.CreateWaveFile(toWaveFilePath, resampler);
        }
    }
}

and modify your program like this:

 static void Main()
 {
    ConvertWav("C:/input.wav","C:/output.wav");
 } 

Upvotes: 0

Amelia B
Amelia B

Reputation: 1084

It might be added and sorry I can't comment yet due to lack of points. That NAudio ALWAYS writes 46 byte headers which in certain situations can cause crashes. I want to add this in case someone encouters this while searching for a clue why naudio wav files only start crashing certain programs.

I encoutered this problem after figuring out how to convert and/or sample wav with NAudio and was stuck after for 2 days now and only figured it out with a hex editor.

(The 2 extra bytes are located at byte 37 and 38 right before the data subchunck [d,a,t,a,size<4bytes>]. Here is a comparison of two wave file headers left is saved by NAudio 46 bytes; right by Audacity 44 bytes

You can check this back by looking at the NAudio src in WaveFormat.cs at line 310 where instead of 16 bytes for the fmt chunck 18+extra are reserved (+extra because there are some wav files which even contain bigger headers than 46 bytes) but NAudio always seems to write 46 byte headers and never 44 (MS standard). It may also be noted that in fact NAudio is able to read 44 byte headers (line 210 in WaveFormat.cs)

Upvotes: 1

Sergey Malyutin
Sergey Malyutin

Reputation: 1554

Not sure if this is the optimal way, but it works...

    public static byte[] ConvertWavTo8000Hz16BitMonoWav(byte[] inArray)
    {
        using (var mem = new MemoryStream(inArray))
        {
            using (var reader = new WaveFileReader(mem))
            {
                using (var converter = WaveFormatConversionStream.CreatePcmStream(reader))
                {
                    using (var upsampler = new WaveFormatConversionStream(new WaveFormat(8000, 16, 1), converter))
                    {
                        byte[] data;
                        using (var m = new MemoryStream())
                        {
                            upsampler.CopyTo(m);
                            data = m.ToArray();
                        }
                        using (var m = new MemoryStream())
                        {
                            // to create a propper WAV header (44 bytes), which begins with RIFF 
                            var w = new WaveFileWriter(m, upsampler.WaveFormat);
                            // append WAV data body
                            w.Write(data,0,data.Length);
                            return m.ToArray();
                        }   
                    }
                }
            }
        }
    }

Upvotes: 3

Related Questions