音频在现实中一些序列振动的波形,如果转化为电压信号,则是电压的振动信号。通过麦克风进行输入时,需要对电压信号进行采样,因此就有一个采样频率的概念。根据奈斯特定理,采样频率需要大于2倍的信号最高频率,其单位为Hz,意思是每秒样本数。而在windows系统中,还有个“sample”-即样本的概念,所谓样本,就是每一次采样时得到的电压信号,并且以二进制的形式存储。根据采样精度的不同,每个样本可以采用不同的位数进行存储,比如8位或者12位,当然是位数越高也能真实反映声音的变化细节了。在多数机器上有两个喇叭(左、右),这就是两个不同的声道,通过将不同数据放入不同声道,将会在左声道和右声道得到不同的播放声音。在系统中,操作系统提供了方便的双声道操作方法。并且左右声道的样本数据都是交错存储,即按照左、右、左、右、......的顺序存储。
比如CD品质的音频采样频率是44100 Hz,而样本位数为16bits,这说明1MB的音频数据可需要播放6秒的时间,即1MB/2/44100=1024*1024/2/44100/2=5.944。第一个2是说一个样本有2字节,而第二个2说明是双声道,也就是每次采样都是采样两个声道。
/* MMTIME data structure */
typedef struct mmtime_tag
{
UINT wType; /*指明联合体中的数据类型*/
union
{
DWORD ms; /* 毫秒 */
DWORD sample; /*采样率*/
DWORD cb; /* 字节数*/
DWORD ticks; /* MIDI流中的滴答数*/
/* SMPTE */
struct
{
BYTE hour; /* 小时*/
BYTE min; /* 分钟*/
BYTE sec; /* 秒*/
BYTE frame; /* 帧 */
BYTE fps; /* 帧/秒 */
BYTE dummy; /* 填充字节 */
#ifdef _WIN32
BYTE pad[2];
#endif
} smpte;
/* MIDI */
struct
{
DWORD songptrpos; /* 歌曲指针位置 */
} midi;
} u;
} MMTIME, *PMMTIME, NEAR *NPMMTIME, FAR *LPMMTIME;
其中的wType可以取值如下:
#define TIME_MS 0x0001 /*以毫秒为单位的时间*/
#define TIME_SAMPLES 0x0002 /* 波形采样数 */
#define TIME_BYTES 0x0004 /* 当前字节偏移量*/
#define TIME_SMPTE 0x0008 /* SMPTE 时间 */
#define TIME_MIDI 0x0010 /* MIDI时间*/
#define TIME_TICKS 0x0020 /* MIDI流中的滴答*/
多媒体扩展的windows消息
#define MM_JOY1MOVE 0x3A0 /* 游戏杆 */
#define MM_JOY2MOVE 0x3A1
#define MM_JOY1ZMOVE 0x3A2
#define MM_JOY2ZMOVE 0x3A3
#define MM_JOY1BUTTONDOWN 0x3B5
#define MM_JOY2BUTTONDOWN 0x3B6
#define MM_JOY1BUTTONUP 0x3B7
#define MM_JOY2BUTTONUP 0x3B8
#define MM_MCINOTIFY 0x3B9 /* MCI */
#define MM_WOM_OPEN 0x3BB /* 波形输出 */
#define MM_WOM_CLOSE 0x3BC
#define MM_WOM_DONE 0x3BD
#define MM_WIM_OPEN 0x3BE /*波形输入 */
#define MM_WIM_CLOSE 0x3BF
#define MM_WIM_DATA 0x3C0
#define MM_MIM_OPEN 0x3C1 /* MIDI 输入 */
#define MM_MIM_CLOSE 0x3C2
#define MM_MIM_DATA 0x3C3
#define MM_MIM_LONGDATA 0x3C4
#define MM_MIM_ERROR 0x3C5
#define MM_MIM_LONGERROR 0x3C6
#define MM_MOM_OPEN 0x3C7 /* MIDI 输出 */
#define MM_MOM_CLOSE 0x3C8
#define MM_MOM_DONE 0x3C9
几个重要的结构
typedef struct tagWAVEOUTCAPSA {
WORD wMid; /* 生产商ID*/
WORD wPid; /*产品ID */
MMVERSION vDriverVersion; /* 驱动器版本*/
CHAR szPname[MAXPNAMELEN]; /* 产品名称,以NULL结尾的字符串*/
DWORD dwFormats; /* 支持的格式*/
WORD wChannels; /*支持的通道数 */
WORD wReserved1; /* 保留 */
DWORD dwSupport; /* 驱动器支持的功能*/
} WAVEOUTCAPS
/* 波形数据块头*/
typedef struct wavehdr_tag {
LPSTR lpData; /* 锁定数据缓冲的指针 */
DWORD dwBufferLength; /* 数据缓冲区的长度*/
DWORD dwBytesRecorded; /* 只用于输入y */
DWORD_PTR dwUser; /* 客户端使用 */
DWORD dwFlags; /* 排序标志,查看flags定义*/
DWORD dwLoops; /* 循环控制计数器*/
struct wavehdr_tag FAR *lpNext; /* 保留用于驱动程序 */
DWORD_PTR reserved; /* 保留用于驱动程序*/
} WAVEHDR, *PWAVEHDR, NEAR *NPWAVEHDR, FAR *LPWAVEHDR;
/*
* 用于所有非PCM格式的扩展波形格式,此结构对于所有的非PCM格式数据都是通用的*/
typedef struct tWAVEFORMATEX
{
WORD wFormatTag; /* 格式类型 */
WORD nChannels; /* 通道数量,比如单声道,立体声*/
DWORD nSamplesPerSec; /* 采样率 */
DWORD nAvgBytesPerSec; /* 用于缓冲估计*/
WORD nBlockAlign; /* 数据块大小 */
WORD wBitsPerSample; /* 单一数据块每个采样的数据位数*/
WORD cbSize; /* cbSize之后的数据大小,单位为字节。注:cbSize后面跟着数据 */
} WAVEFORMATEX, *PWAVEFORMATEX, NEAR *NPWAVEFORMATEX, FAR *LPWAVEFORMATEX;
打开声音设备需要使用WaveOutOpen函数,其原型为
WINMMAPI MMRESULT WINAPI waveOutOpen(LPHWAVEOUT phwo, UINT uDeviceID, LPCWAVEFORMATEX pwfx, DWORD_PTR dwCallback, DWORD_PTR dwInstance, DWORD fdwOpen)
参数介绍:
phwo-一个指向音频设备句柄的指针,如果fdwOpen设置为WAVE_FORMAT_QUERY,则这个参数可以设置为NULL。
uDeviceID-音频设备输出设备ID,也可以设置为WAVE_MAPPER,这时程序会根据波形数据格式自行选择打开合适的设备。
pwfx-WAVEFORMATEX结构的指针,包含要申请的波形格式
dwCallback-可以是回调函数地址,事件句、窗口句柄或一个将在波形音频回放时以便处理与回放进度相关消息的线程ID,如果不需要这些功能,则可以将其设置为NULL。
dwInstance-回调函数的实例数据,如果dwCallback为窗口句柄,则没有此参数
fwOpen-打开设置的选项,可选项有:
CALLBACK_EVENT dwCallback 参数栏是事件柄
CALLBACK_FUNCTION dwCallback 参数栏是CALLBACK过程地址
CALLBACK_NULL 默认的设置,即无CALLBACK进程
CALLBACK_THREAD dwCallback 参数栏是线程ID
CALLBACK_WINDOW dwCallback 参数栏是窗口柄
WAVE_ALLOWSYNC 如果该项被设置,一个同步的设备能被打开。如果在打开一个同步驱动时没有用该项,设备打开将会失败
WAVE_FORMAT_DIRECT 如果设定该项,则ACM驱动器将不会对音频数据进行格式转换
WAVE_FORMAT_QUERY 如果设定该项,waveOutOpen询问设备来决定是否支持给定的格式,但设备实际上并没有被打开。
WAVE_MAPPED 该项被设定后uDeviceID参数表示一个被音频设备映射的波形设备。
没有评论:
发表评论