InvalidParameter calling acmStreamPrepareHeader

Feb 23, 2009 at 9:50 PM
Using the latest NAudio code base, and using the body of code below to convert a wav file... inside an NUnit Test I receive NO exceptions and the conversion is successful, however inside a Console Application I receive the exception below:

using (WaveFileReader sourceStream = new WaveFileReader(location))
using (WaveStream pcmStream = WaveFormatConversionStream.CreatePcmStream(sourceStream))
  using (WaveFormatConversionStream stream = new WaveFormatConversionStream(new WaveFormat(8000, 8, 1), pcmStream))
    WaveFileWriter.CreateWaveFile("somefile", stream);

calling WaveFileWriter.CreateWaveFile(...) produces:

Unhandled Exception: NAudio.MmException: InvalidParameter calling acmStreamPrepareHeader
   at NAudio.MmException.Try(MmResult result, String function)
   at NAudio.Wave.Compression.AcmStreamHeader.Prepare()
   at NAudio.Wave.Compression.AcmStreamHeader.Convert(Int32 bytesToConvert, Int32& sourceBytesConverted)
   at NAudio.Wave.Compression.AcmStream.Convert(Int32 bytesToConvert, Int32& sourceBytesConverted)
   at NAudio.Wave.WaveFormatConversionStream.Read(Byte[] array, Int32 offset, Int32 count)

I have debugged both sets of code, but do not see anything odd. What am I missing?
Feb 24, 2009 at 9:54 AM

That certainly is a strange problem. Is it definitely the same file you are trying to convert each time? Does it convert any of the file before raising the exception? What compression is the original WAV file using?

Feb 24, 2009 at 3:36 PM
Hello Mark, This exception occurs with ANY file.

I used a different overloaded method for waveFormatConversionStream.Read() and passed in a WaveBuffer but received the following exception:

I set up the following Console Application code in a new project in your solution:

using NAudio.Wave;
namespace NAudioConsole
    class Program
        static void Main(string[] args)
            IWaveBuffer buffer = new WaveBuffer(new byte[0]);

which produces the following exception:

"Could not load type 'NAudio.Wave.WaveBuffer' from assembly 'NAudio, Version=, Culture=neutral, PublicKeyToken=null' because it contains an object field at offset 4 that is incorrectly aligned or overlapped by a non-object field."

I am on a 64 bit OS, which may be why this exception and the prior occurs. This is currently beyond me, but I did change the FieldOffset to 8 rather than 4 and the exception about field offset disappeared.

Feb 24, 2009 at 5:10 PM
I found these:

"Strange 64-bit error with LayoutKind.Explicit"

"TypeLoadException on x64 but is fine on x86 with structlayouts"

As a work-around I set the Console Application "Platform Target" as x86 and the conversion was successful.

Feb 25, 2009 at 9:18 PM
@geiman - it's been confirmed that this change of Platform Target is required for NAudio on all x64 bit platforms. You will get odd exceptions arising based on what you do and if you debug the calls it normally occurs at the time of invoking a local platform API.
Feb 26, 2009 at 3:54 PM
Yes, I will try to check in a new version with x86 as the Platform Target soon which will have to do until I can properly test and address all the issues with a native x64 build. Thanks for reporting this though.

Feb 26, 2009 at 11:29 PM
Thanks Mark, much appreciated.
Mar 28, 2009 at 10:02 AM
Edited Mar 29, 2009 at 6:38 AM
I was able to successfully run subset of NAudio sources on Vista x64. The modification is required in declaration of AcmStreamHeaderStruct
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
    internal class AcmStreamHeaderStruct {
        internal int cbStruct;
        internal int fdwStatus = 0;
        internal IntPtr userData = IntPtr.Zero;
        internal IntPtr sourceBufferPointer;
        internal int sourceBufferLength;
        internal int sourceBufferLengthUsed;
        internal IntPtr sourceUserData = IntPtr.Zero;
        internal IntPtr destBufferPointer;
        internal int destBufferLength;
        internal int destBufferLengthUsed = 0;
        internal IntPtr destUserData = IntPtr.Zero;

        internal IntPtr reserved0;
        internal IntPtr reserved1;
        internal IntPtr reserved2;
        internal IntPtr reserved3;
        internal IntPtr reserved4;
        internal IntPtr reserved5;
        internal IntPtr reserved6;
       internal IntPtr reserved7;
       internal IntPtr reserved8;
        internal IntPtr reserved9;
 and in AcmStreamHeader.Prepare()
    streamHeader.cbStruct = Marshal.SizeOf(streamHeader);