最近需要用到Microsoft Audio Compression Manager (ACM), 鉴于C#.NET没有直接的ACM的API,自己写了pinvoke:
public const string msacm = "msacm32.dll";
[DllImport(msacm, CharSet = CharSet.Unicode)]
public static extern MMRESULT acmStreamOpen(out IntPtr phas, IntPtr had,
ref WAVEFORMATEX pwfxSrc, ref WAVEFORMATEX pwfxDest, IntPtr pwFltr/*WAVEFILTER pwFltr*/, IntPtr
callBack, IntPtr dwInstance, [MarshalAs(UnmanagedType.U4)] uint dwOpen);
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct WAVEFORMATEX
{
public UInt16 wFormatTag; /* format type */
public UInt16 nChannels; /* number of channels (i.e. mono, stereo...) */
public UInt32 nSamplesPerSec; /* sample rate */
public UInt32 nAvgBytesPerSec; /* for buffer estimation */
public UInt16 nBlockAlign; /* block size of data */
public UInt16 wBitsPerSample; /* number of bits per sample of mono data */
public UInt16 cbSize; /* the count in bytes of the size of */
/* extra information (after cbSize) */
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class WAVEFILTER
{
public UInt32 cbStruct; /* Size, in bytes, of the WAVEFILTER structure */
public UInt32 pcdwFilterTag; /* Waveform-audio filter type */
public UInt32 fdwFilter; /* Flags for the dwFilterTag member. */
[MarshalAs(UnmanagedType.SysUInt, SizeConst = 5)]
public UInt32 dwReserved; /* Reserved for system use */
}
Some tips about using ACM:
1. 有些ACM Driver支持有回调函数也就是异步转换,有些不支持,在使用acmStreamOpen函数的时候要注意。
2. 只有ACM Driver支持的格式间才可以相互转换,否则acmStreamOpen 会返回 512。
3. 使用acmStreamOpen 的例子:
ACMController.MMRESULT Result = ACMController.acmStreamOpen(out _hACMStream, _hACMDriver, ref F.Wfx, ref _DestWaveFormat, IntPtr.Zero, IntPtr.Zero, //_Window.Handle IntPtr.Zero, 0 /* ACMController.ACM_STREAMOPENF_ASYNC | ACMController.CALLBACK_WINDOW */);
如果_DestWaveFormat 是WAVE-PCM 格式的话可以按如下设置:
_DestWaveFormat.wFormatTag = ACMController.WAVE_FORMAT_PCM; _DestWaveFormat.nChannels = f.Wfx.nChannels; (depend on ACM Driver) _DestWaveFormat.nSamplesPerSec = f.Wfx.nSamplesPerSec; (depend on ACM Driver)
_DestWaveFormat.wBitsPerSample = 16; (depend on ACM Driver)
_DestWaveFormat.nBlockAlign = (ushort)(_DestWaveFormat.nChannels * Math.Ceiling((double)_DestWaveFormat.wBitsPerSample / 8)); _DestWaveFormat.nAvgBytesPerSec = _DestWaveFormat.nSamplesPerSec * _DestWaveFormat.nBlockAlign; _DestWaveFormat.cbSize = 0;
4. 一些查看ACM Driver 的例子:
pInvoke:
[DllImport(msacm)] public static extern MMRESULT acmDriverEnum(AcmDriverEnumCallback fnCallback, int dwInstance, AcmDriverEnumFlags flags); [DllImport(msacm)] public static extern MMRESULT acmDriverDetails(int hAcmDriver, ref AcmDriverDetails driverDetails, int reserved); [DllImport(msacm)] public static extern MMRESULT acmDriverID(IntPtr has, int hAcmDriver, int reserved);
public delegate bool AcmDriverEnumCallback(int hAcmDriverId, int instance, AcmDriverDetailsSupportFlags flags);
使用:
_ACMdrivers = new List<ACMController.AcmDriverDetails>(); Result = ACMController.acmDriverEnum(new ACMController.AcmDriverEnumCallback(DriverEnumCallback), 0, 0); foreach (ACMController.AcmDriverDetails mdriver in _ACMdrivers) { int n = 0; }
private bool DriverEnumCallback(int hAcmDriver, int dwInstance, ACMController.AcmDriverDetailsSupportFlags flags) { ACMController.AcmDriverDetails details = new ACMController.AcmDriverDetails(); details.structureSize = System.Runtime.InteropServices.Marshal.SizeOf(details); ACMController.MMRESULT R= ACMController.acmDriverDetails(hAcmDriver, ref details, 0); _ACMdrivers.Add(details); return true; }