0
votes

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)?

2

2 Answers

2
votes

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);
}
0
votes

I believe I found which conversions and in what order the conversions need to be in for this to work properly. The below code seems to be working.

String inputWav = "D:\\test-input.wav";
String tempWav = "D:\\test-input-temp.wav";
String outputWav = "D:\\test-output.wav";

WaveFormat pcm8k16bit = new WaveFormat(8000, 16, 1);
WaveFormat muLaw8k8bit = WaveFormat.CreateMuLawFormat(8000, 1);

using (var reader = new WaveFileReader(inputWav))
using (var conversionStream = new WaveFormatConversionStream(pcm8k16bit, reader))
{
    WaveFileWriter.CreateWaveFile(tempWav, conversionStream);
}

using (var fs = new FileStream(tempWav, FileMode.Open))
using (var rawSrcReader = new RawSourceWaveStream(fs, pcm8k16bit))
using (var conversionStream = new WaveFormatConversionStream(muLaw8k8bit, rawSrcReader))
{
    WaveFileWriter.CreateWaveFile(outputWav, conversionStream);
}

The problem is that I still can't figure out why this is the case. I tried many other arrangements of the same and similar code to no avail. For example, why does the conversion fail when converting from PCM 48kHz/8bit to MuLaw 48kHz/8bit?