class winmm
{
[StructLayout(LayoutKind.Sequential)]
public struct WAVEFORMATEX
{
public WaveFormat wFormatTag;
public UInt16 nChannels;
public UInt32 nSamplesPerSec;
public UInt32 nAvgBytesPerSec;
public UInt16 nBlockAlign;
public UInt16 wBitsPerSample;
public UInt16 cbSize;
}
[StructLayout(LayoutKind.Sequential)]
public struct WAVEHDR
{
public IntPtr lpData;
public UInt32 dwBufferLength;
public UInt32 dwBytesRecorded;
public IntPtr dwUser;
public UInt32 dwFlags;
public UInt32 dwLoops;
public IntPtr lpNext;
public IntPtr reserved;
}
[Flags]
public enum WaveOpenFlags
{
CALLBACK_NULL = 0,
CALLBACK_FUNCTION = 0x30000,
CALLBACK_EVENT = 0x50000,
CallbackWindow = 0x10000,
CallbackThread = 0x20000,
WAVE_FORMAT_DIRECT = 0x0008
}
public enum WaveMessage
{
WIM_OPEN = 0x3BE,
WIM_CLOSE = 0x3BF,
WIM_DATA = 0x3C0,
WOM_CLOSE = 0x3BC,
WOM_DONE = 0x3BD,
WOM_OPEN = 0x3BB
}
public enum WaveFormat : ushort
{
WAVE_FORMAT_PCM = 0x0001,
}
public static IntPtr WAVE_MAPPER { get; } = (IntPtr)(-1);
public delegate void WaveCallback(IntPtr hwi, uint uMsg, uint dwInstance, uint dwParam1, uint dwParam2);
[DllImport("winmm.dll")]
public static extern int waveOutOpen(out IntPtr IntPtr, uint uDeviceID, WAVEFORMATEX lpFormat,
WaveCallback dwCallback, int dwInstance, int dwFlags);
[DllImport("winmm.dll")]
public static extern int waveOutSetVolume(IntPtr hwo, ushort dwVolume);
[DllImport("winmm.dll")]
public static extern int waveOutClose(in IntPtr IntPtr);
[DllImport("winmm.dll")]
public static extern int waveOutPrepareHeader(IntPtr IntPtr, in WAVEHDR lpWaveOutHdr, int uSize);
[DllImport("winmm.dll")]
public static extern int waveOutUnprepareHeader(IntPtr IntPtr, in WAVEHDR lpWaveOutHdr, int uSize);
[DllImport("winmm.dll")]
public static extern int waveOutWrite(IntPtr IntPtr, in WAVEHDR lpWaveOutHdr, int uSize);
}
public unsafe class PcmPlayer
{
IntPtr _hwo = IntPtr.Zero;
private IntPtr free_pwfx = IntPtr.Zero;
winmm.WAVEFORMATEX _wfx;
public PcmPlayer(int channels, int sampleRate, int sampleSize)
{
_wfx = new winmm.WAVEFORMATEX
{
wFormatTag = winmm.WaveFormat.WAVE_FORMAT_PCM,
nChannels = (ushort)channels,
nSamplesPerSec = (ushort)sampleRate,
wBitsPerSample = (ushort)sampleSize
};
_wfx.nBlockAlign = (ushort)(_wfx.nChannels * _wfx.wBitsPerSample / 8);
_wfx.nAvgBytesPerSec = _wfx.nBlockAlign * _wfx.nSamplesPerSec;
this.free_pwfx = MarshalUtils.CreateStructurePointer(_wfx);
}
public void Open(winmm.WaveCallback wavecall )
{
winmm.waveOutOpen(out _hwo, 0xFFFFFFFF,
_wfx, wavecall, 0,
waveIn.WAVE_FORMAT_DIRECT | waveIn.CALLBACK_FUNCTION);
}
winmm.WAVEHDR _wh;
private bool def = false;
public void WriteData(byte[] buffer)
{
_wh = new winmm.WAVEHDR();
_wh.lpData = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, 0);
_wh.dwBufferLength = (uint)buffer.Length;
_wh.dwFlags = 0;
_wh.dwLoops = 1;
winmm.waveOutPrepareHeader(_hwo, _wh, sizeof(winmm.WAVEHDR));
winmm.waveOutWrite(_hwo, _wh, sizeof(winmm.WAVEHDR));
}
public void Dispose()
{
winmm.waveOutUnprepareHeader(_hwo, _wh, sizeof(winmm.WAVEHDR));
winmm.waveOutClose(_hwo);
_hwo = IntPtr.Zero;
}
}