波形文件数据的读取

如果需要从底层来控制和操作波形文件,就需要获取波形文件的声音的采样数据。RIFF格式文件与普通文件不同,不能像打开普通文件一样打开RIFF文件。幸好,VC为读取多媒体文件提供了专门用来操作RIFF格式文件的I/OB函数,这些多媒体I/O函数都以mmio开头,包括打开,关闭,写入,创建新数据块等一系列的操作。

读取WAV文件的一般流程:
1.读取文件需要通过mmioOpen打开波形文件,打开的方式很简单,如下所示:
HMMIO h;
h = mmioOpen(path, NULL, MMIO_READ_WRITE);
mmioOpen函数可以打开一个标准文件,内存文件或用户存储系统,该函数返回的指针类型HMMIO是一个多媒体文件句柄,HMMIO句柄不是标准的文件句柄,只能用于多媒体文件I/O函数。函数中的path表示一个波形文件的有效路径,MMIO_READ_WRITE表示以可读写的方式打开文件。NULL对应的参数为指向特殊参数的MMIOINFO结构指针,通常被设为NULL。




WAV文件的格式

偏移量

字节

数据

波形块的大小文件大小减

格式块的大小字节

波形文件大小

波形数据开始

2. 打开文件后,可通过HMMO句柄获得文件中的波形部份:
MMCKINFO mmckinfo;
mmckinfo.fccType = mmioFOURCC('W','A','V','E');
mmioDescend(h, &mmckinfo, NULL, MMIO_FINDRIFF);
经上述调用,mmioDescend函数在句柄h所指向的文件中搜索构造类型为"WAVE"的块的信息,MMCKINFO结构用来接受波形部份信息。该函数调用时会通过检查MMCKINFO结构的fccType的数据来决定需要获得什么构造类型的信息。我们指定函数的wflags参数为MMIO_FINDRIFF,表示需要搜索"RIFF"块信息。
RIFF文件的块信息结构MMCKINFO的定义如下:
typedef struct 
{
    FOURCC ckid;                // 记录块的标识
    DWORD cksize;             // 记录该块的数据长度,该长度不包含4字节的块标识长度
    FOURCC fccType;          // 记录块的类型
    DWORD dwDataOffset; // 记录块数据成员的首地址距文件头的偏移量
    DOWRD dwFlags;          // 用来指定块的附加信息,一般为空或MMIO_DIRTY等标记
}MMCKINFO;

3. 得到波形部分的MMCKINFO结构指针后,下一步就是获得波形文件的信息部分:
MMCKINFO mmfmtckinfo;
mmfmtckinfo.ckid = mmioFOURCC('F','M','T',' ');
mmioDescend(h, &mmfmtckinfo, &mmckinfo, MMIO_FINDCHUNCK);

4. 同样采用mmioDescend函数,但调用的结果不同,该函数可以通过把"RIFF"块mmckinfo作为"父块",以块搜索块的方式搜索到构造类型为"fmt "。搜索到的块信息由mmfmtckinfo对象接受。MMIO_FINDCHUNCK标识表示搜索块信息,h为传入多媒体文件的句柄。
MMCKINFO结构中的fccType成员为四字节数据,如果类型不满4个字符,应该往后面添加空格。

5. 得到了fmt部分的MMCKINFO指针后需要通过mmfmtckinfo得到PCMWAVEFORMAT结构:
PCMWAVEROMAT wformat;
mmioRead(h, &wformat, mmfmtckinfo.cksize);
当文件指针指到多媒体文件的mmfmtckinfo部分,函数会自动搜索到需要读入的PCMWAVEFORMT结构首地址,并按首地址顺次向wformat填满mmfmtckinfo.cksize大小的字符数。函数成功调用后,得到非空的PCMWAVEFORMAT对象wformat,并返回读出的字节总数,否则mmioRead返回-1,表示读操作出错.

6. 如果还需要得到波形文件的数据信息,也就是说,要得到data部分信息,也可以通过调用mmioDescend函数得以实现。实现的第一步使文件的当前位置退回到mmckinfo块的位置:
mmioAscend(h, &mmfmtckinfo, 0);
然后需要声明一个对象mmdatainfo,并把该对象的fccType成员设置为"data"类型。通过mmioDescend函数搜索到data部分的地址:
MMCKINFO mmdatainfo;
mmdatainfo.ckid = mmioFOURCC('d','a', 't', 'a');
mmioDescend(h, &mmdatainfo, &mmckinfo, MMIO_FINDCHUNK);
HGLOBAL hdata;
LPSTR      pdata;
hdata = GlobalAlloc(GMEM_MOVEALBE, mmdatainfo.cksize);
pdata = (LPSTR)GlobalLock(hdata);
mmioRead(h, pdata, mmdatainfo.cksize);

7. GlobalAlloc函数用来得到固定大小数据块的指针,该指针指向的空间没有实际含义的对象存在。GlobalLock函数通过锁定由GlobalAlloc函数得到的数据块,把hdata句柄转换成为内存指针。mmioRead(h, pdata, mmdatainfo,.cksize)语句用来向pdata地址读入mmdatainfo.cksize大小的数据。
GlobalAlloc函数原型为:
HGLOBAL GlobalAlloc
(
    UINT uFlags;           // allocation attributes
    DWORD dwBytes; // numbers of bytes to allocate 
)
(1). uFlags为分配属性标识。各表示含义如下:
GMEM_FIXED表示分配固定的内在空间;
GMEM_MOVEABLE表示分配可变内存空间
GMEM_SHARE 表示可以使用DDE操作
GMEM_DISCARABLE 只用于和16位Windows相兼容的应用中,表示该内存块是可被释放的,采用该标识必须用GlobalDiscard函数来释放块;
GMEM_ZEROIIT用于把内在块的大小初始化为0。如果uFlags取0,表示分配固定的内在空间。
(2). dwBytes 指定分配内存大小。
GlobalLock函数原型:
LPVOID GlobalLock
(
    HGLOBAL hMem; // handle to the global memory object
)
(3). hMem为GlobalAlloc函数返回的句柄,GlobalLock函数返回内存指针。

以上7个马骤后,得到了波形文件的数据信息,并把数据信息读入到内存中,通过对指针pdata指向内存块的访问,我们就可以随意地访问该内存块的任何信息。

你可能感兴趣的:(编程语言,开发环境,VC)