waveOutPrepareHeader возвращает INVALPARAMS - PullRequest
2 голосов
/ 10 февраля 2012

Я пытался отследить это некоторое время, но я не знаю, где искать дальше. Всякий раз, когда я вызываю waveOutPrepareHeader (), я получаю INVALPARAMS, указывающий «Базовый адрес буфера не выровнен с размером выборки».

В настоящее время я готовлю свой заголовок из данных после тега «data» (и длины) из файла, используя метод, найденный через MSDN.

    public Wave.SystemError Read(BinaryReader rdr, uint readLength)
    {
        dwBufferLength = readLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED,
               (uint)data.Length);

        if (lpData == IntPtr.Zero)
            return Wave.SystemError.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return Wave.SystemError.NOERROR;
    }

Все параметры класса обнуляются перед использованием, после вызова этой функции в волновом файле я получаю

dwBufferLength = 32768
dwBytesRecorded = 0
dwFlags = 0
dwLoops = 0
dwUser = 0
lpData = 384656
lpNext = 0
reserved = 0

при передаче в

return waveOutPrepareHeader(hWaveOut, 
                            ref headerBuffer[buffIndex],
                            (uint)Marshal.SizeOf(headerBuffer[buffIndex]));

где headerBuffer [buffIndex] - вышеупомянутый WAVEHDR, который я получаю 11 (MMSYSERR_INVALPARAM). Я проверил, и мой hWaveOut и размер кажутся нормальными, поэтому я вынужден сделать вывод, что проблема с заголовком, но я не могу понять, что не так или даже что проверить.

Что мне нужно сделать, чтобы исправить эту ошибку или, если это не удалось, что я могу проверить, чтобы выяснить, что ее вызывает? Любая помощь будет принята с благодарностью

Ответы [ 2 ]

2 голосов
/ 10 февраля 2012

Ваш размер выборки больше 1 байта?Если это так, то ...

в ARM важно сохранять данные выровненными, поэтому, если вы выделите буфер BYTE (один байт), а затем приведете его к SHORT (два байта), то если буфер BYTE был выделен нанечетный адрес, тогда вы получите доступ к данным без выравнивания.

Так что, если ваш размер выборки составляет два байта, вы должны убедиться, что ваш буферный адрес BYTE всегда четный.

Чтобы проверить это, вы можете проверить, какое значение имеет lpData при появлении ошибки, если она нечетная, просто выделите еще 1 байт и отправьте буфер + 1 в функцию winapi.


нижепример кода с правильным выравниванием, найденный по адресу: http://www.utdallas.edu/~nsg051000/AmbientNoise4/Wave.cs

    ///  
    /// Read a data buffer from the supplied BinaryReader.  This method will 
    /// allocate memory for the data buffer it is not already allocated. 
    ///  
    /// BinaryReader containing data 
    /// Size, in bytes, to be read 
    /// MMSYSERR.NOERROR if successful 
    public MMSYSERR Read(BinaryReader rdr, uint readLength, int align)
    {
        uint bufferLength = readLength;

        if (bufferLength % align != 0)
            bufferLength += (uint)(align - (bufferLength % align));

        dwBufferLength = bufferLength;
        byte[] data = new byte[readLength];
        rdr.Read(data, 0, data.Length);

        if (lpData == IntPtr.Zero)
            lpData = Memory.LocalAlloc(Memory.LMEM_FIXED, (uint)bufferLength);

        if (lpData == IntPtr.Zero)
            return MMSYSERR.NOMEM;

        Marshal.Copy(data, 0, lpData, data.Length);

        return MMSYSERR.NOERROR;
    }
1 голос
/ 14 февраля 2012

В итоге проблема заключалась не в lpData (которая была правильно выделена LocalAlloc), а в том, как сама структура WAVEHDR передавалась в PInvoked waveOutPrepareHeader.

В большинстве материалов в waveOut (даже для C #) вы передаете объект типа заголовка. Но чтобы перестать получать ошибку, мне пришлось создать блок данных с помощью Marshal.AllocHGlobal и скопировать в него заголовок с помощью Marshal.StructureToPtr. IntPtr из AllocHGlobal затем передается в waveOutPrepareHeader как таковой, что решает проблему.

Вот примерный пример кода для тех, кто столкнулся с подобной проблемой.

WAVEHDR header = new WAVEHDR();
//Read or setup header data here
IntPtr headerPtr = Marshal.AllocHGlobal(Marshal.SizeOf(header));
Marshal.StructureToPtr(header, headerPtr, true);
waveOutPrepareHeader(hWaveOut, headerPtr, (uint)Marshal.SizeOf(header));

Это предполагает, что вы устанавливаете свой PInvoke для всего, что использует заголовок, типа IntPtr вместо WAVEHDR.

Оттуда используйте headerPtr для всех мест, где вам нужно передать этот заголовок. Вам придется самостоятельно справиться с освобождением памяти в соответствующем месте, как и следовало ожидать.

...