2011年5月25日星期三

  VS2008中的声卡编程

音频在现实中一些序列振动的波形,如果转化为电压信号,则是电压的振动信号。通过麦克风进行输入时,需要对电压信号进行采样,因此就有一个采样频率的概念。根据奈斯特定理,采样频率需要大于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参数表示一个被音频设备映射的波形设备。

没有评论:

发表评论