Search code examples
c#naudioaudio-converter

wav file conversion PCM 48kHz/16 bit rate to u-law 8kHz/8 bit rate using NAudio


I have a wav file that I need to convert into a format that can be read by one of our applications. The file I want to convert is in the format:

  • Encoding: PCM
  • Sample Rate: 48kHz
  • Bit Rate: 16 bits
  • Channels: 1

The readable file format I want to convert to is:

  • Encoding: u-Law
  • Sample Rate: 8kHz
  • Bit Rate: 8 bits
  • Channels: 1

To accomplish this, I'm using the NAudio library. The code I'm using for the conversion is something along the lines of:

using (WaveFileReader reader = new WaveFileReader(inputWavFilePath))
{
    WaveFormat newFormat = WaveFormat.CreateMuLawFormat(8000, 1);
    using (var conversionStream = new WaveFormatConversionStream(newFormat, reader))
    {
        WaveFileWriter.CreateWaveFile(outputWavFilePath, conversionStream);
    }
}

The above conversion throws the error

AcmNotPossible calling acmStreamOpen

I've seen a few links for converting from u-law to PCM, but am having trouble with the reverse.

What I'm struggling to understand is why when I convert PCM/48kHz/16bit -> uLaw/48kHz/8bit the exception is not thrown. But, when I then try to convert the resulting file to uLaw/8kHz/8bit the exception is thrown.

I'm new to working with audio files and different formats, so my apologies if I'm missing something simple.

Could someone please explain why the conversion is only throwing the exception at the sample rate conversion and not at the other two conversions (encoding PCM -> uLaw && 16bit -> 8bit)?


Solution

  • I wrote a fairly detailed article to explain how to convert between various audio types in .NET (many using NAudio)

    With ACM codecs, you can usually only change one thing at a time - e.g.

    • Changing the sample rate (e.g. 48kHz -> 8kHz)
    • Changing the channel count (e.g. mono -> stereo)
    • Changing the bit depth (e.g. 32 bit float -> 16 bit integer)
    • Encoding or decoding with a codec (e.g. going from PCM to mu-law)

    You can chain them together to perform a two-stage conversion - e.g. like this:

    using (var reader = new WaveFileReader(inputWav))
    using (var conversionStream1 = new WaveFormatConversionStream(pcm8k16bit, reader))
    using (var conversionStream2 = new WaveFormatConversionStream(muLaw8k8bit, conversionStream1))
    {
        WaveFileWriter.CreateWaveFile(outputWav, conversionStream2);
    }