📄 wave.cs
字号:
/// by this demo.
/// </summary>
public const int WAVE_FORMAT_PCM = 1;
/// <summary>
/// Managed implementation of the WAVEFORMATEX structure.
/// WAVEFORMATEX defines the format of waveform-audio data. Only format
/// information common to all waveform-audio data formats is included in
/// this structure. For formats requiring additional information, this
/// structure is included as the first member in another structure, along
/// with the additional information.
/// </summary>
public class WAVEFORMATEX
{
/// <summary>
/// Waveform-audio format type. Format tags are registered with
/// Microsoft Corporation for many compression algorithms. A
/// complete list of format tags is located in the Mmsystem.h
/// header file.
/// </summary>
public ushort wFormatTag = 0;
/// <summary>
/// Number of channels in the waveform-audio data. Monaural data
/// uses one channel and stereo data uses two channels.
/// </summary>
public ushort nChannels = 0;
/// <summary>
/// Sample rate, in samples per second (hertz), that each channel
/// should be played or recorded. If wFormatTag is WAVE_FORMAT_PCM,
/// then common values for nSamplesPerSec are 8.0 kHz, 11.025 kHz,
/// 22.05 kHz, and 44.1 kHz. For non-PCM formats, this member must
/// be computed according to the manufacturer's specification of the
/// format tag.
/// </summary>
public uint nSamplesPerSec = 0;
/// <summary>
/// Required average data-transfer rate, in bytes per second, for the
/// format tag. If wFormatTag is WAVE_FORMAT_PCM, nAvgBytesPerSec
/// should be equal to the product of nSamplesPerSec and nBlockAlign.
/// For non-PCM formats, this member must be computed according to the
/// manufacturer's specification of the format tag. Playback and record
/// software can estimate buffer sizes by using the nAvgBytesPerSec
/// member.
/// </summary>
public uint nAvgBytesPerSec = 0;
/// <summary>
/// Block alignment, in bytes. The block alignment is the minimum
/// atomic unit of data for the wFormatTag format type. If wFormatTag
/// is WAVE_FORMAT_PCM, nBlockAlign should be equal to the product of
/// nChannels and wBitsPerSample divided by 8 (bits per byte). For non-
/// PCM formats, this member must be computed according to the
/// manufacturer's specification of the format tag. Playback and record
/// software must process a multiple of nBlockAlign bytes of data at a
/// time. Data written and read from a device must always start at the
/// beginning of a block. For example, it is illegal to start playback
/// of PCM data in the middle of a sample (that is, on a non-block-
/// aligned boundary).
/// </summary>
public ushort nBlockAlign = 0;
/// <summary>
/// Bits per sample for the wFormatTag format type. If wFormatTag is
/// WAVE_FORMAT_PCM, then wBitsPerSample should be equal to 8 or 16.
/// For non-PCM formats, this member must be set according to the
/// manufacturer's specification of the format tag. Some compression
/// schemes cannot define a value for wBitsPerSample, so this member
/// can be zero.
/// </summary>
public ushort wBitsPerSample = 0;
/// <summary>
/// Seeks the provided stream to the start of this structure, assuming
/// that the stream represents a .wav file.
/// </summary>
/// <param name="fs">Stream representing .wav data</param>
public void SeekTo(Stream fs)
{
fs.Seek(WF_OFFSET_FORMATTAG, SeekOrigin.Begin);
}
/// <summary>
/// Seeks the provided stream to the location immediately following this
/// structure, assuming that the stream represents a .wav file.
/// </summary>
/// <param name="fs">Stream representing .wav data</param>
public void Skip(Stream fs)
{
fs.Seek(WF_OFFSET_DATA, SeekOrigin.Begin);
}
/// <summary>
/// Read this structure from the provided stream. To access this
/// data from a .wav file, use the SeekTo method before calling this
/// method.
/// </summary>
/// <param name="rdr">BinaryReader representing .wav data</param>
/// <returns>Length, in bytes of the PCM data in the file</returns>
public uint Read(BinaryReader rdr)
{
wFormatTag = rdr.ReadUInt16();
nChannels = rdr.ReadUInt16();
nSamplesPerSec = rdr.ReadUInt32();
nAvgBytesPerSec = rdr.ReadUInt32();
nBlockAlign = rdr.ReadUInt16();
wBitsPerSample = rdr.ReadUInt16();
// Unused subchunk Id and size
uint dummy = rdr.ReadUInt32();
return rdr.ReadUInt32();
}
}
/// <summary>
/// Managed implementation of the WAVEHDR structure.
/// This structure defines the header used to identify a waveform-audio
/// buffer.
/// </summary>
public class WAVEHDR : IDisposable
{
/// <summary>
/// Long pointer to the address of the waveform buffer. This buffer
/// must be block-aligned according to the nBlockAlign member of the
/// WAVEFORMATEX structure used to open the device.
/// </summary>
public IntPtr lpData = IntPtr.Zero;
/// <summary>
/// Specifies the length, in bytes, of the buffer.
/// </summary>
public uint dwBufferLength = 0;
/// <summary>
/// When the header is used in input, this member specifies how much
/// data is in the buffer.
/// </summary>
public uint dwBytesRecorded = 0;
/// <summary>
/// Specifies user data.
/// </summary>
public uint dwUser = 0;
/// <summary>
/// Specifies information about the buffer.
/// </summary>
public uint dwFlags = 0;
/// <summary>
/// Specifies the number of times to play the loop. This member is
/// used only with output buffers.
/// </summary>
public uint dwLoops = 0;
/// <summary>
/// Reserved.
/// </summary>
public IntPtr lpNext = IntPtr.Zero;
/// <summary>
/// Reserved.
/// </summary>
public uint reserved = 0;
/// <summary>
/// Read the specified length of waveform data into
/// the lpData member. This method will also allocate the
/// buffer if it is not already allocated or is too small
/// for the data.
/// </summary>
/// <param name="rdr">BinaryReader representing the
/// waveform data.</param>
/// <param name="readLength">Length of data to be read</param>
/// <returns>Error condition of read attempt</returns>
public MMSYSERR 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 MMSYSERR.NOMEM;
Marshal.Copy(data, 0, lpData, data.Length);
return MMSYSERR.NOERROR;
}
/// <summary>
/// Initialize a data buffer in lpData of the specified length.
/// </summary>
/// <param name="bufferLength">Size of buffer to allocate</param>
/// <param name="init">If true, set the data to 0's</param>
/// <returns>Error condition of initialization attempt</returns>
public MMSYSERR Init(uint bufferLength, bool init)
{
if (lpData != IntPtr.Zero && dwBufferLength < bufferLength)
{
Memory.LocalFree(lpData);
lpData = IntPtr.Zero;
}
if (lpData == IntPtr.Zero)
lpData = Memory.LocalAlloc(Memory.LMEM_FIXED, bufferLength);
dwBufferLength = bufferLength;
if (lpData == IntPtr.Zero)
return MMSYSERR.NOMEM;
if (init)
{
for (int i = 0; i < bufferLength; i++)
{
Marshal.WriteByte(lpData, i, 0);
}
}
return MMSYSERR.NOERROR;
}
/// <summary>
/// Re-initialize the header. This resets all members but leaves
/// the data pointer as is.
/// </summary>
public void Reinit()
{
dwBytesRecorded = 0;
dwUser = 0;
dwFlags = 0;
dwLoops = 0;
lpNext = IntPtr.Zero;
reserved = 0;
}
/// <summary>
/// Clean up any resources allocated for the header.
/// </summary>
public void Dispose()
{
if (lpData != IntPtr.Zero)
Memory.LocalFree(lpData);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -