为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

2016新编WAV文件格式分析详解

2017-09-21 50页 doc 173KB 21阅读

用户头像

is_686908

暂无简介

举报
2016新编WAV文件格式分析详解2016新编WAV文件格式分析详解 WAV文件格式分析详解 一、综述 WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准 的。 RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件 的头四个字节便是“RIFF”。 WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图: -----------------...
2016新编WAV文件格式分析详解
2016新编WAV文件格式分析详解 WAV文件格式分析详解 一、综述 WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准 的。 RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件 的头四个字节便是“RIFF”。 WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图: ------------------------------------------------ | RIFF WAVE Chunk | | ID = 'RIFF' | | RiffType = 'WAVE' | ------------------------------------------------ | Format Chunk | | ID = 'fmt ' | ------------------------------------------------ | Fact Chunk(optional) | | ID = 'fact' | ------------------------------------------------ | Data Chunk | | ID = 'data' | ------------------------------------------------ 图1 Wav格式包含Chunk示例 其中除了Fact Chunk外,其他三个Chunk是必须的。每个Chunk有各自的 ID,位于Chunk最开始位置,作为标示,而且均为4个字节。并且紧跟在ID后 面的是Chunk大小(去除ID和Size所占的字节数后剩下的其他字节数目),4 个字节表示,低字节表示数值低位,高字节表示数值高位。下面具体介绍各个 Chunk内容。 PS: 所有数值表示均为低字节表示低位,高字节表示高位。 二、具体介绍 RIFF WAVE Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'RIFF' | ---------------------------------- | Size | 4 Bytes | | ---------------------------------- | Type | 4 Bytes | 'WAVE' | ---------------------------------- 图2 RIFF WAVE Chunk 以'FIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小 减去ID和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段, 为'WAVE',表示是wav文件。 结构定义如下: struct RIFF_HEADER { char szRiffID[4]; // 'R','I','F','F' DWORD dwRiffSize; char szRiffFormat[4]; // 'W','A','V','E' }; Format Chunk =============================================================== | | 字节数 | 具体内 容 | ================================================================= | ID | 4 Bytes | 'fmt ' | ----------------------------------------------------------------- | Size | 4 Bytes | 数值为16或18,18则最后又附加信 息 | ----------------------------------------------------------- ---- | FormatTag | 2 Bytes | 编码方式,一般为 0x0001 | | -------------------------------------------------------------------- | | Channels | 2 Bytes | 声道数目,1--单声道;2--双声 道 | | -------------------------------------------------------------------- | | SamplesPerSec | 4 Bytes | 采样频 率 | | -------------------------------------------------------------------- | | AvgBytesPerSec| 4 Bytes | 每秒所需字节 数 | |===> WAVE_FORMAT -------------------------------------------------------------------- | | BlockAlign | 2 Bytes | 数据块对齐单位(每个采样需要的字节数) | | ----------------------------------------------------------------- --- | | BitsPerSample | 2 Bytes | 每个采样需要的bit 数 | | ----------------------------------------------------------------- --- | | | 2 Bytes | 附加信息(可选,通过Size来判断有无) | | ----------------------------------------------------------------- --- ---- 图3 Format Chunk 以'fmt '作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18 则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的 附加信息。 结构定义如下: struct WAVE_FORMAT { WORD wFormatTag; WORD wChannels; DWORD dwSamplesPerSec; DWORD dwAvgBytesPerSec; WORD wBlockAlign; WORD wBitsPerSample; }; struct FMT_BLOCK { char szFmtID[4]; // 'f','m','t',' ' DWORD dwFmtSize; WAVE_FORMAT wavFormat; }; Fact Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'fact' | ---------------------------------- | Size | 4 Bytes | 数值为4 | ---------------------------------- | data | 4 Bytes | | ---------------------------------- 图4 Fact Chunk Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。 结构定义如下: struct FACT_BLOCK { char szFactID[4]; // 'f','a','c','t' DWORD dwFactSize; }; Data Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'data' | ---------------------------------- | Size | 4 Bytes | | ---------------------------------- | data | | | ---------------------------------- 图5 Data Chunk Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是 数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数, wav数据的bit位置可以分成以下几种形式: ----------------------------------------------------------------- ---- | 单声道 | 取样1 | 取样2 | 取样3 | 取样4 | | |---------------------------------------------------- ---- | 8bit量化 | 声道0 | 声道0 | 声道0 | 声道0 | ----------------------------------------------------------------- ---- | 双声道 | 取样1 | 取样 2 | | |---------------------------------------------------- ---- | 8bit量化 | 声道0(左) | 声道1(右) | 声道0(左) | 声道 1(右) | ----------------------------------------------------------------- ---- | | 取样1 | 取样2 | | 单声 道 |-------------------------------------------------------- | 16bit量化 | 声道0 | 声道0 | 声道0 | 声道0 | | | (低位字节) | (高位字节) | (低位字节) | (高位字节) | ----------------------------------------------------------------- ---- | | 取样 1 | | 双声 道 |-------------------------------------------------------- | 16bit量化 | 声道0(左) | 声道0(左) | 声道1(右) | 声道1(右) | | | (低位字节) | (高位字节) | (低位字节) | (高位字 节) | ----------------------------------------------------------------- ---- 图6 wav数据bit位置安排方式 Data Chunk头结构定义如下: struct DATA_BLOCK { char szDataID[4]; // 'd','a','t','a' DWORD dwDataSize; }; 三、小结 因此,根据上述结构定义以及格式介绍,很容易编写相应的wav格式解析代码。 这里具体的代码就不给出了。 WAV文件格式研究笔记 WAV文件格式是(WAV From format)的简写。WAV是指文件格式,而数据编码格式是多样的, 目前微软提供的数据格式只有一种PCM -脉派编码调变(Pulse Code Modulation也就是最常见的无压缩WAV)。其他的数据格式有G.723.1、ACELP、CCITT A-Law、CCITT u-Law、TrueSpeed(TM)、GSM 6.10等,这些格式大多数是为电话或调制解调器等低速语音为主的设备而使用,它们一般采用比较窄的采样范围来产生比较大的压缩比,并没有统一标准。不在本文讨论范围。 ?RIFF文件和WAV文件格式 在Windows环境下,大部分的多媒体文件都依循着一种结构来存放信息,这种结构称为"资源互换文件格式"(Resources lnterchange File Format),简称RIFF。例如声音的WAV文件、视频的AV1文件等等均是由此结构衍生出来的。RIFF可以看做是一种树状结构,其基本构成单位为chunk,犹如树状结构中的节点,每个chunk由"辨别码"、"数据大小"及"数据"所组成。 辨别码(ID)由4个ASCII码所构成,数据大小则标示出紧跟其后数据的长度(单位为Byte),而数据大小本身也用掉4个Byte,所以事实上一个chunk的长度为数据大小加8。一般而言,chunk本身并不允许内部再包含chunk,但有两种例外,分别为以"RIFF"及"LIST"为辨别码的chunk。而针对此两种chunk,RIFF又从原先的"数据"中切出4个Byte。 此4个Byte称为"格式辨别码",然而RIFF又规定文件中仅能有一个以"RIFF"为辨别码的chunk。 ?文件结构 WAV文件是chunk的集合,其中有两个chunk是不可缺少的,分别是“fmt”(format)和“data”chunk,fmt装载的是wav文件的各项参数,如采样率。data chunk装载的是音频数据。其他的chunk则是可选的。 所有音频应用程序必须能读取这两个主要的chunk,所有音频复制程序必须能复制所有chunk。 chunk在文件中的顺序是不受限制的,除了一条规则:fmt chunk必须在data chunk前面。 绝大部分人写程序的时候都以为fmt chunk必须放在文件的开头,紧跟riff标识。实际上这并不是必须的,因为微软白皮书没要求如此。但这样搞也没错。 下图显示一个简单的WAV文件结构 __________________________ | riff wave chunk | | groupid = 'riff' | | rifftype = 'wave' | | __________________ | | | format chunk | | | | ckid = 'fmt ' | | | |__________________| | | __________________ | | | sound data chunk | | | | ckid = 'data' | | | |__________________| | |__________________________| ?数据类型 所有数据存储在8bit字节中,按照intel 80x86 (ie, little endian)方式排列,多字节排列顺序如 下。 7 6 5 4 3 2 1 0 +-----------------------+ char: | lsb msb | +-----------------------+ 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 +-----------------------+-----------------------+ short: | lsb byte 0 | byte 1 msb | +-----------------------+-----------------------+ 7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 21 20 19 18 17 16 31 30 29 28 27 26 25 24 +-----------------------+-----------------------+-----------------------+-----------------------+ long: | lsb byte 0 | byte 1 | byte 2 | byte 3 msb | +-----------------------+-----------------------+-----------------------+-----------------------+ ?采样频率,采样精度,声道数量 采样频率(sample rate):1秒钟采样的次数。采样次数越多,越能细分声音的频率。音质越 好。 采样精度(bit resolution):(采样精度、采样位数、采样值或取样值,随便你怎么叫)用 来描述每次采样结果的空间大小。也就是用多大的取值范围去描述一个采样点的值(振幅)。 精度越高,对声音的分辨力越强。 声道数量(channels):那就是声道数量... ?采样点和采样帧(sample point and sample frame) 采样点是描述某个时刻的声音样本。采样精度就是这个时间上声音的振幅可以用多大的取值 空间描述。16bit的采样精度取值范围是-32768 (0x8000)到32767 (0x7fff)。中点,也就是静 音点是0。但对于8bit的采样精度来说,范围却是从0-255,静音点在128。(为何有这样的 差异,问比盖去。他的人弄的) 因为cpu读数据都是用8bit的byte做单位。所以如果你用的是9-16bit的精度,每个采样点 用2byte。17-24bit用3byte,25-32bit就用4byte双word。按左对齐,空出的bit补0(pad 部分)。具体排列方式按下图。 ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ | | | | | | | | | | | | | | | | | | 1 0 1 0 0 0 0 1 0 1 1 1 0 0 0 0 | |___|___|___|___|___|___|___|___|___|___|___|___|___|___|___|___| <---------------------------------------------> <-------------> 12bit 采样点按照左对齐方式先排满左边 右面4bit补0(pad) 注意,根据intel little endian存储顺序,按byte为单位从左到右从小到大,因此存到介质上 面应该是下面这个顺序: ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ ___ | | | | | | | | | | | | | | | | | | | 0 1 1 1 0 0 0 0 | | 1 0 1 0 0 0 0 1 | |___|___|___|___|___|___|___|___| |___|___|___|___|___|___|___|___| <-------------> <-------------> <-----------------------------> bits 0 to 3 4 pad bits bits 4 to 11 如果当前的WAV文件是多声道的怎么办, 假如是2声道的,先放左边声道的采样点,然后放右面声道的。接着是下一个时刻的左声道 采样点。这样用两个采样点分别表示左右声道,在播放的时候同一时间播放出来。那么一个 时刻上的采样点的集合就成为采样帧。单声道文件每个采样帧包括1个采样点,两声道的采 样帧就有2个采样点。如此类推。 sample sample sample frame 0 frame 1 frame n _____ _____ _____ _____ _____ _____ | ch1 | ch2 | ch1 | ch2 | . . . | ch1 | ch2 | |_____|_____|_____|_____| |_____|_____| _____ | | = one sample point |_____| 下面是大于两声道的情况下的排列标准。 channels 1 2 _________ _________ | left | right | stereo | | | |_________|_________| 1 2 3 _________ _________ _________ | left | right | center | 3 channel | | | | |_________|_________|_________| 1 2 3 4 _________ _________ _________ _________ | front | front | rear | rear | quad | left | right | left | right | |_________|_________|_________|_________| 1 2 3 4 _________ _________ _________ _________ | left | center | right | surround| 4 channel | | | | | |_________|_________|_________|_________| 1 2 3 4 5 6 _________ _________ _________ _________ _________ _________ | left | left | center | right | right |surround | 6 channel | center | | | center | | | |_________|_________|_________|_________|_________|_________| note:以上为无压缩WAVE格式排列方式。显然这样的方式可压缩空间很大(否则也不会跑 出ape这类无损压缩格式了)。如果是有压缩格式,则不一定适用上述规则。 ?the format chunk format(fmt)chunk 描述了WAVEFROM数据的基本参数,例如采样频率,精度,声道数 量等等。 #define formatid 'fmt ' /* chunkid for format chunk. note: 因为ID是4字节,所以fmt后面 有个空格~切记 */ typedef struct ...{ id chunkid; long chunksize; short wformattag; unsigned short wchannels; unsigned long dwsamplespersec; unsigned long dwavgbytespersec; unsigned short wblockalign; unsigned short wbitspersample; /**//* note: there may be additional fields here, depending upon wformattag. */ } formatchunk; chunkid:永远是'fmt ' chunksize:大小,不包括chunkid和chunksize占用的8个字节,单位是byte wformattag:如果data chunk里面的数据是无压缩的话,那么每个采样帧和每个采样点的长 度应该是固定并且符合上面的采样点规定的,但如果是有压缩的话,这就不一定了。 wformattag就是用来标识是否有压缩的。在无压缩的情况下,wformattag的值是1,并且没 有fmt chunk没有附加fields(further fields)。wformattag不等于1的其他情况下的处理方式 要看微软网站。 wchannels:就是声道数量。1、2、3、4、6... dwsamplespersec:采样频率、每秒采样次数。单位赫兹。标准的取值如 11025, 22050, and 44100。 dwavgbytespersec:每秒采样数据的空间大小,也就是正常播放的话,每秒要读多少数据。 用来方便程序评估留多大缓冲区。dwavgbytespersec的值必须根据下列公式。 dwavgbytespersec = round(dwsamplespersec * wblockalign) wblockalign:块对齐位,值从以下公式得出。 wblockalign = round(wchannels * (wbitspersample % 8)) 基本上说,wblockalign就等于采样帧大小。wbitspersample就是采样率。 每个合法的WAV文件都必须有唯一的一个fmt chunk。 ?data chunk 放声音数据的地方了。 #define dataid 'data' /* chunk id for data chunk */ typedef struct ...{ id chunkid; long chunksize; unsigned char waveformdata[]; } datachunk; chunkid:永远是data chunksize:不包括chunkid,和chunksize占用的8个字节。 waveformdata:这个数组里面每个元素就是一个采样帧,大小看wblockalign 每个合法的WAV文件都必须有唯一的一个data chunk。 运用多媒体WAV文件格式二三例 多媒体技术近年来发展很快,较好品质的声卡可以提供16位的立体声及44KHZ的播放录制能力,它不仅可以提供原音逼真的取样,其合成的音质也十分理想,有的声卡还加入了数字信号处理器,可编程控制的DSP具有强大的运算能力,它可以用来作声音信息的压缩和一些特殊效果的处理。具有此功能的声卡提供的WAV文件提供的语音信息可以满足语音特征识别的要求。 1.1 RIFF文件和WAV文件格式 在Windows环境下,大部分的多媒体文件都依循着一种结构来存放信息,这种结构称为"资源互换文件格式"(Resources lnterchange File Format),简称RIFF。例如声音的WAV文件、视频的AV1文件等等均是由此结构衍生出来的。RIFF可以看做是一种树状结构,其基本构成单位为chunk,犹如树状结构中的节点,每个chunk由"辨别码"、"数据大小"及"数据"所组成。 辨别码由4个ASCII码所构成,数据大小则标示出紧跟其后数据的长度(单位为Byte),而数据大小本身也用掉4个Byte,所以事实上一个chunk的长度为数据大小加8。一般而言,chunk本身并不允许内部再包含chunk,但有两种例外,分别为以"RIFF"及"L1ST"为辨别码的chunk。而针对此两种chunk,RIFF又从原先的"数据"中切出4个Byte。 此4个Byte称为"格式辨别码",然而RIFF又规定文件中仅能有一个以"RIFF"为辨别码的chunk。 只要依循此一结构的文件,我们均称之为RIFF档。此种结构提供了一种系统化的分类。如果和MS一DOS文件系统作比较,"RIFF"chunk就好比是一台硬盘的根目录,其格式辨别码便是此硬盘的逻辑代码(C:或D:),而"L1ST"chunk即为其下的子目录,其他的chunk则为一般的文件。至于在RIFF文件的处理方面,微软提供了相关的函数。视窗下的各种多媒体文件格式就如同在磁盘机下规定仅能放怎样的目录,而在该目录下仅能放何种数据。 WAV为WAVEFORM(波形)的缩写。声音文件的结构如图1所示,"RIFF"的格式辨别码为"WAVE"。整个文件由两个chunk所组 成:辨别码"fmt"(注意,最后一个是空白字符!)及"data"。 在"fmt"的chunk下包含了一个PCMWAVEFORMAT数据结构,其定义如下: typedef struct pcmwaveformat - tag { WAVEFORMAT wf ; WORD wBitsPerSample; } PCMWAVEFORMAT; typedef struct waveformat - tag { WORD wFormatTag ; WORD nChannels; DWORD nSamplesPerSec; DWORD nAvgBytesperSec; WORD nBlockAlign; } WAVEFORMAT; 其意义分别为: wFormatTag:记录着此声音的格式代号,例如WAVE_FORMAT_PCM,WAVE_F0RAM_ADPCM等等。 nChannels:记录声音的频道数。 nSamp1esPerSec:记录每秒取样数。 nAvgBytesPerSec:记录每秒的数据量。 nBlockA1ign:记录区块的对齐单位。 wBitsPerSample:记录每个取样所需的位元数。 "data"Chunk包含真正的声音数据。Window目前仅提供WAVE_FORMAT_PCM一种数据格式,所代表的意义是脉派编码调变 (Pu1se Code Modulation)。针对此格式,Windows定义了在"data"的chunk中数据的存放情形,图2中列出了四种不同频道数 及取样所需的位元数以及位元位置的安排。 "RIFF" 频道0 频道0 频道0 频道0 xxxx nChannels=1,wBitsPerSample=8 "WAVE" 频0(左) 频道1(右) 频道0(左) 频道1 (右) "fmt " nChannels=2,wBitsPerSample=8 sizeof(PCMWAVEFORMAT) struct of PCMWAVEFORMAT 频道0(低位) 频道0(高位) 频道0(低位)频道0(高位) "data" nChannels=1,wBitsPerSample=16 xxxx 频道0(低位) 频道0(高位) 频道0(低位)频道0(高位) (低位) (高位) (低位) (高位) wave form data nChannels=2,wBitsPerSample=16 图1 WAV文件结构 图2 PCM文件中位元安排方式 第一排表示单声道8位元,第二排表示双声道8位元,第三排表示单声道16位元,第四排表示双声道16位元。8位元代表音量大小由8个位元所表示,16位元则代表音量大小由16个位元所表示。理论上8位元可以表示0,255,16位元可表示0,65536,不过windows却定16位元其值的范围从-32168,32167。此外尚有一点要注意的是,0并不一定代表无声,而是由中间的数值来决定,也就是在8位元时为128,16位元时为0才是无声。所以,若程序设计时需放入无声的数据,糯特别注意声音格式是16或是8位元,以放入适当的值。 1.2 WAV文件信息的具体应用 WAV文件中包括了对原始声音的高速率采样,并且以WAVE_PCM_FORMAT脉派编码调变格式,我们可以在VISUAL C++程序中实现,在读出WAVEHDR文件头之后,下面就是原始声音的高速率采样信息,我们可以对它作多方面的信息处理。 1.2.1 波形显示。 我们可以以时域-幅度的方式显示出原始声音的波形,这是最简单同时也是最直接的信息处理方式。在时域范围内,我们可以观察该信号波形是否连续,中间是否有跳变等。 1.2.2频谱显示 我们可以以频域-幅度的方式显示出原始声音的频谱,在对原始信号经过FFT变换之后,可以得到该信号的频谱,进而得到该信号的能量集中带,分布特征,谱对称系数等等。 1.2.3 用于语音信号识别 讲话者的个体识别是语音信号处理的一个重要内容,但它的一个前提条件是必须提供语音信号的数字波形,通常的方法是将原始的语音信号进行放大、抗混叠滤波、A/D采样、数值编码,最终得到语音信号的数字波形,通常多采用硬件处理,费时费力,如果我们借助非常成熟的声卡技术,将WAV文件打开,就非常方便地得到语音信号的数字波形,为下一步进行语音信号识别提供良好的前端预处理。 基于VisuaC++6.0的声音文件操作 声音是人类传递信息的重要途径,如果应用程序中包含声音信息,就可以大大增强它的亲合力;另外在科研开发过程中,声音信号的处理也是一个很重要的科学研究领域。Visual C++作为一个强大的开发工具,当然是声音处理的首选工具,但是在当前Visual C++相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,笔者结合自己的学习和开发过程中积累的一些经验,在本实例中来和广大编程爱好者们探讨一下声音文件的处理,当然本实例也不可能包括声音处理内容的方方面面,只是希望它能够对刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。 当前计算机系统处理声音文件有两种办法:一是使用现成的软件,如微软的录音机、SoundForge、CoolEdit等软件可以实现对声音信号进行录音、编辑、播放的处理,但它们的功能是有限的,为了更灵活,更大限度地处理声音数据,就不得不使用另外一种方法,既利用微软提供的多媒体服务,在Windows环境下自己编写程序来进行声音处理来实现一些特定的功能。下面就开始介绍声音文件的格式和在Windows环境下使用Visual C++开发工具进行声音文件编程处理的方法。 一、实现方法 1、RIFF文件结构和WAVE文件格式 Windows支持两种RIFF(Resource Interchange File Format,"资源交互文件格式")格式的音频文件:MIDI的RMID文件和波形音频文件格式WAVE文件,其中在计算机领域最常用的数字化声音文件格式是后者,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav",因而该类文件也被称为WAVE文件。为了突出重点,有的放矢,本文涉及到的声音文件所指的就是WAVE文件。常见的WAVE语音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。这里的采样率是指声音信号在进行"模?数"转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。在进行声音编程处理以前,首先让我们来了解一下RIFF文件和WAVE文件格式。 RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的,每个块有"标志符"、"数据大小"及"数据"所组成,块的结构如图1所示: 块的标志符(4BYTES) 数据大小 (4BYTES) 数据 图一、 块的结构示意图 从上图可以看出,其中"标志符"为4个字符所组成的代码,如"RIFF","LIST"等,指定块的标志ID;数据大小用来指定块的数据域大小,它的尺寸也为4个字符;数据用来描述具体的声音信号,它可以由若干个子块构成,一般情况下块与块是平行的,不能相互嵌套,但是有两种类型的块可以嵌套子块,他们是"RIFF"或"LIST"标志的块,其中RIFF块的级别最高,它可以包括LIST块。另外,RIFF块和LIST块与其他块不同,RIFF块的数据总是以一个指定文件中数据存储格式的四个字符码(称为格式类型)开始,如WAVE文件有一个"WAVE"的格式类型。LIST块的数据总是以一个指定列表内容的4个字符码(称为列表类型)开始,例如扩展名为".AVI"的视频文件就有一个"strl"的列表类型。RIFF和LIST的块结构如下: RIFF/LIST标志符 数据1大小 格式/列表类型 数据1 数据 图二、RIFF/LIST块结构 WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。 WAVE文件的结构如下图三所示: 标志符(RIFF) 数据大小 格式类型("WAVE") "fmt" Sizeof(PCMWAVEFORMAT) PCMWAVEFORMAT "data" 声音数据大小 声音数据 图三、WAVE文件结构 PCMWAVEFORMAT结构定义如下: Typedef struct { WAVEFORMAT wf;//波形格式; WORD wBitsPerSample;//WAVE文件的采样大小; }PCMWAVEFORMAT; WAVEFORMAT结构定义如下: typedef struct { WORD wFormatag;//编码格式,包括WAVE_FORMAT_PCM, WAVEFORMAT_ADPCM等 WORD nChannls;//声道数,单声道为1,双声道为2; DWORD nSamplesPerSec;//采样频率; DWORD nAvgBytesperSec;//每秒的数据量; WORD nBlockAlign;//块对齐; }WAVEFORMAT; "data"子块包含WAVE文件的数字化波形声音数据,其存放格式依赖于"fmt"子块中wForma tTag成员指定的格式种类,在多声道WAVE文件中,样本是交替出现的。如16bit的单声道WA VE文件和双声道WAVE文件的数据采样格式分别如图四所示: 16位单声道: 采样二 „„ 采样一 高字节 低字节 高字节 低字节 „„ 16位双声道: „„ 采样一 右声道 „„ 左声道 高字节 低字节 高字节 低字节 „„ 图四、WAVE文件数据采样格式 2、声音文件的声音数据的读取操作 操作声音文件,也就是将WAVE文件打开,获取其中的声音数据,根据所需要的声音数据处理算法,进行相应的数学运算,然后将结果重新存储与WAVE格式的文件中去。可以使用CFILE类来实现读取操作,也可以使用另外一种方法,拿就是使用Windows提供的多媒体处理函数(这些函数都以mmino打头)。这里就介绍如何使用这些相关的函数来获取声音文件的数据,至于如何进行处理,那要根据你的目的来选择不同的算法了。WAVE文件的操作流程如下:1)调用mminoOpen函数来打开WAVE文件,获取HMMIO类型的文件句柄;2)根据WAVE文件的结构,调用mmioRead、mmioWrite和mmioSeek函数实现文件的读、写和定位操作;3)调用mmioClose函数来关闭WAVE文件。 下面的函数代码就是根据WAVE文件的格式,实现了读取双声道立体声数据,但是在使用下面的代码过程中,注意需要在程序中链接Winmm.lib库,并且包含头文件"Mmsystem.h"。 BYTE * GetData(Cstring *pString) //获取声音文件数据的函数,pString参数指向要打开的声音文件; { if (pString==NULL) return NULL; HMMIO file1;//定义HMMIO文件句柄; file1=mmioOpen((LPSTR)pString,NULL,MMIO_READWRITE); //以读写模式打开所给的WAVE文件; if(file1==NULL) { MessageBox("WAVE文件打开失败~"); Return NULL; } char style[4];//定义一个四字节的数据,用来存放文件的类型; mmioSeek(file1,8,SEEK_SET);//定位到WAVE文件的类型位置 mmioRead(file1,style,4); if(style[0]!='W'||style[1]!='A'||style[2]!='V'||style[3]!='E') //判断该文件是否为"WAVE"文件格式 { MessageBox("该文件不是WAVE格式的文件~"); Return NULL; } PCMWAVEFORMAT format; //定义PCMWAVEFORMAT结构对象,用来判断WAVE 文件格式; mmioSeek(file1,20,SEEK_SET); //对打开的文件进行定位,此时指向WAVE文件的PCMWAVEFORMAT结构的数据; mmioRead(file1,(char*)&format,sizeof(PCMWAVEFORMAT));//获取该结构的数据; if(format.wf.nChannels!=2)//判断是否是立体声声音; { MessageBox("该声音文件不是双通道立体声文件"); return NULL; } mmioSeek(file1,24+sizeof(PCMWAVEFORMAT),SEEK_SET); //获取WAVE文件的声音数据的大小; long size; mmioRead(file1,(char*)&size,4); BYTE *pData; pData=(BYTE*)new char[size];//根据数据的大小申请缓冲区; mmioSeek(file1,28+sizeof(PCMWAVEFORMAT),SEEK_SET);//对文件重新定位; mmioRead(file1,(char*)pData,size);//读取声音数据; mmioClose(file1, MMIO_FHOPEN);//关闭WAVE文件; return pData; } 3、使用MCI方法操作声音文件 WAVE声音文件一个最基本的操作就是将文件中的声音数据播放出来,用Windows提供的API函数BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound)可以实现小型WAV文件的播放,其中参数lpszSound 为所要播放的声音文件,fuSound为播放声音文件时所用的标志位。例如实现Sound.wav 文件的异步播放,只要调用函数sndPlaySound("c:\windows\Sound.wav",SND_ ASYNC)就可以了,由此可以看到sndPlaySound函数使用是很简单的。但是当WAVE文件大于100K时,这时候系统无法将声音数据一次性的读入内存,sndPlaySound函数就不能进行播放了。为了解决这个问题,你的一个选择就是用MCI方法来操作声音文件了。在使用MCI方法之前,首先需要在你开发的项目设置Project->Setting->Link->Object/library modules中加入winmm.lib。并在头文件中包括"mmsystem.h"头文件。 MicroSoft API提供了MCI(The Media Control Interface)的方法mciSendCommand()和mciSendString()来完成WAVE文件的播放,这里仅介绍mciSendCommand()函数的使用。 原型:DWORD mciSendCommand(UINT wDeviceID,UINT wMessage,DWORD dwParam1,DWORD dwParam2); 参数:wDeviceID:接受消息的设备ID; Message:MCI命令消息; wParam1:命令的标志位; wParam2:所使用参数块的指针 返值:调用成功,返回零;否则,返回双字中的低字存放有错误信息。 在使用MCI播放声音文件时,首先要打开音频设备,为此要定义MCI_OPEN_PARMS变量 OpenParms,并设置该结构的相应分量: OpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_WAVEFORM_AUDIO;//WAVE类型 OpenParms.lpstrElementName = (LPCSTR) Filename;//打开的声音文件名; OpenParms.wDeviceID = 0;//打开的音频设备的ID mciSendCommand (NULL, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_TY PE_ID | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &OpenParms)函数调用发送MCI_OPEN命令后,返回的参数 OpenParms中成员变量的wDeviceID指明打开了哪个设备。需要关闭音频设备时只要调用mciSendCommand (m_wDeviceID, MCI_CLOSE, NULL, NULL)就可以了。 播放WAVE文件时,需要定义MCI_PLAY_PARMS变量PlayParms,对该变量进行如下设置:PlayParms.dwFrom = 0,这是为了指定从什么地方(时间)播放WAVE文件,设置好以后,调用函数mciSendCommand (m_wDeviceID, MCI_PLAY,MCI_FROM, (DWORD)(LPVOID)&PlayP arms));就实现了WAVE声音文件的播放。 另外,调用mciSendCommand (m_wDeviceID, MCI_PAUSE, 0,(DWORD)(LPVOID)&PlayPa rms)实现了暂停功能。调用mciSendCommand (m_wDeviceID, MCI_STOP, NULL, NULL)实现停止功能等,可以看出,这些不同的功能实现都是依靠参数"Message"取不同的值来实现的。 不同的Message和dwParam1、dwParam2的组合还可以实现文件的 跳跃功能。如下面的代码实现了跳转到WAVE文件末端的操作:mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_SEE K_TO_END, NULL)。 4、DirectSound操作WAVE文件的方法 MCI虽然调用简单,功能强大,可以满足声音文件处理的基本需要,但是MCI也有它的缺点,那就是它一次只能播放一个WAVE文件,有时在实际应用中,为了实现混音效果,需要同时播放两个或两个以上的WAVE文件时,就需要使用微软DirectX技术中的DirectSound了,该技术直接操作底层声卡设备,可以实现八个以上WAV文件的同时播放。 实现DirectSound需要以下几个步骤:1.创建及初始化DirectSound;2.设定应用程序的声音设备优先级别方式,一般为DSSCL_NORMAL;2. 将WAV文件读入内存,找到格式块、数据块位置及数据长度;3.创建声音缓冲区;4.载入声音数据;5.播放及停止: 二、编程步骤 1、 启动Visual C++6.0生成一个单文档视图结构的应用程序,将该程序命名为"playsound"; 2、 在程序的主菜单中添加"MCI Play"、"PlaySound"菜单,并使用Class Wizard添加相应的消息响应函说,分别用不同的方法来处理声音文件; 3、 在程序的"Link"设置中添加"dsound.lib、dxguid.lib、winmm.lib"库,程序的视图类中包含"mmsystem.h"文件,程序的Debug目录下添加待播放的声音文件"chimes.wav和sound.wav"; 4、 添加代码,编译运行程序; 三、程序代码 //////////////////////////////////////////////////// void CPlaysoundView::OnMciplay()//下面的代码实现了WAVE声音文件的播放: { // TODO: Add your command handler code here MCI_OPEN_PARMS mciOpenParms; MCI_PLAY_PARMS PlayParms; mciOpenParms.dwCallback=0; mciOpenParms.lpstrElementName="d:\\chimes.wav"; mciOpenParms.wDeviceID=0; mciOpenParms.lpstrDeviceType="waveaudio"; mciOpenParms.lpstrAlias=" "; PlayParms.dwCallback=0; PlayParms.dwTo=0; PlayParms.dwFrom=0; mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(DWORD)(LPV OID)&mciOpenParms);//打开音频设备; mciSendCommand(mciOpenParms.wDeviceID,MCI_PLAY,MCI_WAIT,(DWORD)(LPVOID)&PlayP arms);//播放WAVE声音文件; mciSendCommand(mciOpenParms.wDeviceID,MCI_CLOSE,NULL,NULL);//关闭音频设备; } ////////////////////////////////////////////////////////////////////////////// /*下面的函数利用DirectSound技术实现了一个WAVE声音文件的播放(注意项目设置中要包含 "dsound.lib、dxguid.lib"的内容),代码和注释如下:*/ void CPlaysoundView::OnPlaySound() { // TODO: Add your command handler code here LPVOID lpptr1;//指针1; LPVOID lpPtr2;//指针2; HRESULT hResult; DWORD dwLen1,dwLen2; LPVOID m_pMemory;//内存指针; LPWAVEFORMATEX m_pFormat;//LPWAVEFORMATEX变量; LPVOID m_pData;//指向语音数据块的指针; DWORD m_dwSize;//WAVE文件中语音数据块的长度; CFile File;//Cfile对象; DWORD dwSize;//存放WAV文件长度; //打开sound.wav文件; if (!File.Open ("d://sound.wav", Cfile::modeRead |Cfile::shareDenyNone)) return ; dwSize = File.Seek (0, Cfile::end);//获取WAVE文件长度; File.Seek (0, Cfile::begin);//定位到打开的WAVE文件头; //为m_pMemory分配内存,类型为LPVOID,用来存放WAVE文件中的数据; m_pMemory = GlobalAlloc (GMEM_FIXED, dwSize); if (File.ReadHuge (m_pMemory, dwSize) != dwSize)//读取文件中的数据; { File.Close (); return ; } File.Close (); LPDWORD pdw,pdwEnd; DWORD dwRiff,dwType, dwLength; if (m_pFormat) //格式块指针 m_pFormat = NULL; if (m_pData) //数据块指针,类型:LPBYTE m_pData = NULL; if (m_dwSize) //数据长度,类型:DWORD m_dwSize = 0; pdw = (DWORD *) m_pMemory; dwRiff = *pdw++; dwLength = *pdw++; dwType = *pdw++; if (dwRiff != mmioFOURCC ('R', 'I', 'F', 'F')) return ;//判断文件头是否为"RIFF"字符; if (dwType != mmioFOURCC ('W', 'A', 'V', 'E')) return ;//判断文件格式是否为"WAVE"; //寻找格式块,数据块位置及数据长度 pdwEnd = (DWORD *)((BYTE *) m_pMemory+dwLength -4); bool m_bend=false; while ((pdw < pdwEnd)&&(!m_bend)) //pdw文件没有指到文件末尾并且没有获取到声音数据时继续; { dwType = *pdw++; dwLength = *pdw++; switch (dwType) { case mmioFOURCC('f', 'm', 't', ' ')://如果为"fmt"标志; if (!m_pFormat)//获取LPWAVEFORMATEX结构数据; { if (dwLength < sizeof (WAVEFORMAT)) return ; m_pFormat = (LPWAVEFORMATEX) pdw; } break; case mmioFOURCC('d', 'a', 't', 'a')://如果为"data"标志; if (!m_pData || !m_dwSize) { m_pData = (LPBYTE) pdw;//得到指向声音数据块的指针; m_dwSize = dwLength;//获取声音数据块的长度; if (m_pFormat) m_bend=TRUE; } break; } pdw = (DWORD *)((BYTE *) pdw + ((dwLength + 1)&~1));//修改pdw指针,继续循环; } DSBUFFERDESC BufferDesc;//定义DSUBUFFERDESC结构对象; memset (&BufferDesc, 0, sizeof (BufferDesc)); BufferDesc.lpwfxFormat = (LPWAVEFORMATEX)m_pFormat; BufferDesc.dwSize = sizeof (DSBUFFERDESC); BufferDesc.dwBufferBytes = m_dwSize; BufferDesc.dwFlags = 0; HRESULT hRes; LPDIRECTSOUND m_lpDirectSound; hRes = ::DirectSoundCreate(0, &m_lpDirectSound, 0);//创建DirectSound对象; if( hRes != DS_OK ) return; m_lpDirectSound->SetCooperativeLevel(this->GetSafeHwnd(), DSSCL_NORMAL); //设置声音设备优先级别为"NORMAL"; //创建声音数据缓冲; LPDIRECTSOUNDBUFFER m_pDSoundBuffer; if (m_lpDirectSound->CreateSoundBuffer (&BufferDesc, &m_pDSoundBuffer, 0) == DS_OK) //载入声音数据,这里使用两个指针lpPtr1,lpPtr2来指向DirectSoundBuffer缓冲区的数据,这是为了处理大型WAVE文件而设计的。dwLen1,dwLen2分别对应这两个指针所指向的缓冲区的长度。 hResult=m_pDSoundBuffer->Lock(0,m_dwSize,&lpPtr1,&dwLen1,&lpPtr2,&dwLen2,0); if (hResult == DS_OK) { memcpy (lpPtr1, m_pData, dwLen1); if(dwLen2>0) { BYTE *m_pData1=(BYTE*)m_pData+dwLen1; m_pData=(void *)m_pData1; memcpy(lpPtr2,m_pData, dwLen2); } m_pDSoundBuffer->Unlock (lpPtr1, dwLen1, lpPtr2, dwLen2); } DWORD dwFlags = 0; m_pDSoundBuffer->Play (0, 0, dwFlags); //播放WAVE声音数据; } 四、小结 为了更好的说明DiretSound编程的实现,笔者使用了一个函数来实现所有的操作,当然读者可以将上面的内容包装到一个类中,从而更好的实现程序的封装性,至于如何实现就不需要笔 者多说了,真不明白的话,找本C++的书看看(呵呵)。如果定义了类,那么就可以一次声明多个对象来实现多个WAVE声音文件的混合播放。也许细心的读者朋友会发现,在介绍WAVE文件格式的时候我们介绍了PCMWAVEFORMAT结构,但是在代码的实现读取WAVE文件数据部分,我们使用的却是LPWAVEFORMATEX结构,那末是不是我们有错误呢,其实没有错,对于PCM格式的WAVE文件来说,这两个结构是完全一样的,使用LPWAVEFORMATEX结构不过是为了方便设置DSBUFFERDESC对象罢了。 操作WAVE声音文件的方法很多,灵活的运用它们可以灵活地操作WAVE文件,这些函数的详细用途读者可以参考MSDN。本实例只是对WAVE文件的操作作了一个肤浅的介绍,希望可以对读者朋友起到抛砖引玉的作用。 wav文件格式分析详解 网上有一篇曹京写的《wav文件格式分析详解》已经介绍过wav文件格式,有兴趣的读者可以查阅。wav文件通常包含4段:RIFF、格式段、FACT段和数据段。 PCM数据就放在数据段。只要格式段设置的格式与数据段的数据一致,播放程序就可以正确解析。下面这个数组的数据其实就是一个最小的wav文件。 static const unsigned char wav_template[] = { // RIFF WAVE Chunk 0x52, 0x49, 0x46, 0x46, // "RIFF" 0x30, 0x00, 0x00, 0x00, // 总长度 整个wav文件大小减去ID和Size所占用的字节数 0x57, 0x41, 0x56, 0x45, // "WAVE" // Format Chunk 0x66, 0x6D, 0x74, 0x20, // "fmt " 0x10, 0x00, 0x00, 0x00, // 块长度 0x01, 0x00, // 编码方式 0x01, 0x00, // 声道数目 0x80, 0x3E, 0x00, 0x00, // 采样频率 0x00, 0x7D, 0x00, 0x00, // 每秒所需字节数=采样频率*块对齐字节 0x02, 0x00, // 数据对齐字节=每个样本字节数*声道数目 0x10, 0x00, // 样本宽度 // Fact Chunk 0x66, 0x61, 0x63, 0x74, // "fact" 0x04, 0x00, 0x00, 0x00, // 块长度 0x00, 0xBE, 0x00, 0x00, // Data Chunk 0x64, 0x61, 0x74, 0x61, // "data" 0x00, 0x00, 0x00, 0x00, // 块长度 }; 这个wav文件的数据长度为0。我们要增加PCM数据只要完成以下工作: 在数据段尾增加PCM数据; 修改数据段的块长度,修改RIFF段的总长度; 正确设置格式段的PCM参数。 样本长度可能不是8的整数倍,这时wav文件还是要求样本按照字节对齐。在一个样本中数据是左对齐的,右侧空位用0填充。 pcm2wav只考虑了样本长度是16位的情况。 如果有多个声道,wav文件要求先放样本1的各声道数据,再放样本2的各声道数据,依此类推。因为我没有碰到过处理多声道数据的需求,所以pcm2wav只考虑了单声道。 附上原文 作者:曹京 日期:2006年7月17日 一、综述 WAVE文件作为多媒体中使用的声波文件格式之一,它是以RIFF格式为标准的。 RIFF是英文Resource Interchange File Format的缩写,每个WAVE文件的头四个 字节便是“RIFF”。 WAVE文件是由若干个Chunk组成的。按照在文件中的出现位置包括:RIFF WAVE Chunk, Format Chunk, Fact Chunk(可选), Data Chunk。具体见下图: ------------------------------------------------ | RIFF WAVE Chunk | | ID = 'RIFF' | | RiffType = 'WAVE' | ------------------------------------------------ | Format Chunk | | ID = 'fmt ' | ------------------------------------------------ | Fact Chunk(optional) | | ID = 'fact' | ------------------------------------------------ | Data Chunk | | ID = 'data' | ------------------------------------------------ 图1 Wav格式包含Chunk示例 其中除了Fact Chunk外,其他三个Chunk是必须的。每个Chunk有各自的ID,位 于Chunk最开始位置,作为标示,而且均为4个字节。并且紧跟在ID后面的是Chunk大 小(去除ID和Size所占的字节数后剩下的其他字节数目),4个字节表示,低字节 表示数值低位,高字节表示数值高位。下面具体介绍各个Chunk内容。 PS: 所有数值表示均为低字节表示低位,高字节表示高位。 二、具体介绍 RIFF WAVE Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'RIFF' | ---------------------------------- | Size | 4 Bytes | | ---------------------------------- | Type | 4 Bytes | 'WAVE' | ---------------------------------- 图2 RIFF WAVE Chunk 以'FIFF'作为标示,然后紧跟着为size字段,该size是整个wav文件大小减去ID 和Size所占用的字节数,即FileLen - 8 = Size。然后是Type字段,为'WAVE',表 示是wav文件。 结构定义如下: struct RIFF_HEADER { char szRiffID[4]; // 'R','I','F','F' DWORD dwRiffSize; char szRiffFormat[4]; // 'W','A','V','E' }; Format Chunk ==================================================================== | | 字节数 | 具体内容 | ==================================================================== | ID | 4 Bytes | 'fmt ' | -------------------------------------------------------------------- | Size | 4 Bytes | 数值为16或18,18则最后又附加信息 | -------------------------------------------------------------------- ---- | FormatTag | 2 Bytes | 编码方式,一般为0x0001 | | -------------------------------------------------------------------- | | Channels | 2 Bytes | 声道数目,1--单声道;2--双声道 | | -------------------------------------------------------------------- | | SamplesPerSec | 4 Bytes | 采样频率 | | -------------------------------------------------------------------- | | AvgBytesPerSec| 4 Bytes | 每秒所需字节数 | |===> WAVE_FORMAT -------------------------------------------------------------------- | | BlockAlign | 2 Bytes | 数据块对齐单位(每个采样需要的字节数) | | -------------------------------------------------------------------- | | BitsPerSample | 2 Bytes | 每个采样需要的bit数 | | -------------------------------------------------------------------- | | | 2 Bytes | 附加信息(可选,通过Size来判断有无) | | -------------------------------------------------------------------- ---- 图3 Format Chunk 'fmt '作为标示。一般情况下Size为16,此时最后附加信息没有;如果为18 以 则最后多了2个字节的附加信息。主要由一些软件制成的wav格式中含有该2个字节的 附加信息。 结构定义如下: struct WAVE_FORMAT { WORD wFormatTag; WORD wChannels; DWORD dwSamplesPerSec; DWORD dwAvgBytesPerSec; WORD wBlockAlign; WORD wBitsPerSample; }; struct FMT_BLOCK { char szFmtID[4]; // 'f','m','t',' ' DWORD dwFmtSize; WAVE_FORMAT wavFormat; }; 补充头文件样例说明: 首先是一串“52 49 46 46”这个是Ascii字符“RIFF”,这部分是固定格式,表明这是一个 WAVE文件头。 然后是“E4 3C 00 00”,这个是我这个WAV文件的数据大小,记住这个大小是包括头文件的一部分的,包括除了前面8个字节的所有字节,也就等于文件总字节数减去8。这是一个DWORD,我这个文件对应是15588。 然后是“57 41 56 45 66 6D 74 20”,也是Ascii字符“WAVEfmt”,这部分是固定格式。 然后是PCMWAVEFORMAT部分,可以对照一下上面的struct定义,首先就是一个WAVEFORMAT的struct。 随后是“10 00 00 00”,这是一个DWORD,对应数字16,这个对应定义中的Sizeof(PCMWAVEFORMAT),后面我们可以看到这个段内容正好是16个字节。 随后的字节是“01 00”,这是一个WORD,对应定义为编码格式“WAVE_FORMAT_PCM”,我们一般用的是这个。 随后的是“01 00”,这是一个WORD,对应数字1,表示声道数为1,这是个单声道Wav。 随后的是“22 56 00 00”,这是一个DWORD,对应数字22050,代表的是采样频率22050。 随后的是“44 AC 00 00”,这是一个DWORD,对应数字44100,代表的是每秒的数据量。 然后是“02 00”,这是一个WORD,对应数字是2,表示块对齐的内容,含义不太清楚。 然后是“10 00”,这是一个WORD,对应WAVE文件的采样大小,数值为16,采样大小为16Bits。 然后是一串“64 61 74 61”,这个是Ascii字符“data”,标示头结束,开始数据区域。 而后是数据区的开头,有一个DWORD,我这里的字符是“C0 3C 00 00”,对应的十进制数为15552,看一下前面正好可以看到,文件大小是15596,其中到“data”标志出现为止的头是40个字节,再减去这个标志的4个字节正好是15552,再往后面就是真正的Wave文件的数据体了,头文件的解析就到这里。 Fact Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'fact' | ---------------------------------- | Size | 4 Bytes | 数值为4 | ---------------------------------- | data | 4 Bytes | | ---------------------------------- 图4 Fact Chunk Fact Chunk是可选字段,一般当wav文件由某些软件转化而成,则包含该Chunk。 结构定义如下: struct FACT_BLOCK { char szFactID[4]; // 'f','a','c','t' DWORD dwFactSize; }; Data Chunk ================================== | |所占字节数| 具体内容 | ================================== | ID | 4 Bytes | 'data' | ---------------------------------- | Size | 4 Bytes | | ---------------------------------- | data | | | ---------------------------------- 图5 Data Chunk Data Chunk是真正保存wav数据的地方,以'data'作为该Chunk的标示。然后是 数据的大小。紧接着就是wav数据。根据Format Chunk中的声道数以及采样bit数, wav数据的bit位置可以分成以下几种形式: --------------------------------------------------------------------- | 单声道 | 取样1 | 取样2 | 取样3 | 取样4 | | | -------------------------------------------------------- | 8bit量化 | 声道0 | 声道0 | 声道0 | 声道0 | --------------------------------------------------------------------- | 双声道 | 取样1 | 取样2 | | |-------------------------------------------------------- | 8bit量化 | 声道0(左) | 声道1(右) | 声道0(左) | 声道1(右) | --------------------------------------------------------------------- | | 取样1 | 取 样2 | | 单声道 |-------------------------------------------------------- | 16bit量化 | 声道0 | 声道0 | 声道0 | 声道0 | | | (低位字节) | (高位字节) | (低位字节) | (高位字节) | --------------------------------------------------------------------- | | 取样1 | | 双声道 |-------------------------------------------------------- | 16bit量化 | 声道0(左) | 声道0(左) | 声道1(右) | 声道1(右) | | | (低位字节) | (高位字节) | (低位字节) | (高位字节) | --------------------------------------------------------------------- 图6 wav数据bit位置安排方式 Data Chunk头结构定义如下: struct DATA_BLOCK { char szDataID[4]; // 'd','a','t','a' DWORD dwDataSize; }; 三、小结 因此,根据上述结构定义以及格式介绍,很容易编写相应的wav格式解析代码。 这里具体的代码就不给出了。 C++ 解析WAVE格式文件信息,并取得播放时间 在使用QT的过程中,需要用到wav文件的长度,就尝试把它的文件格式解析了一下。 查阅了很多资料,发现很多说的不全或比较模糊,在代码后面会有一些经过实际检验的知识 补充。 //头文件主要包括几个数据结构: typedef unsigned short WORD; typedef unsigned long DWORD; struct RIFF_HEADER { char szRiffID[4]; // 'R','I','F','F' DWORD dwRiffSize; //=(size of file) - 8 Byte char szRiffFormat[4]; // 'W','A','V','E' }; struct WAVE_FORMAT { WORD wFormatTag; /* format type */ WORD nChannels; /* number of channels (i.e. mono, stereo...) */ DWORD nSamplesPerSec; /* sample rate */ DWORD nAvgBytesPerSec; /* for buffer estimation */ WORD nBlockAlign; /* block size of data */ WORD wBitsPerSample; /* number of bits per sample of mono data */ //WORD cbSize; /* the count in bytes of the size of */ /* extra information (after cbSize) */ }; struct FMT_BLOCK { char szFmtID[4]; // 'f','m','t',' ' DWORD dwFmtSize; WAVE_FORMAT wavFormat; }; struct DATA_BLOCK { char szDataID[4]; // 'd','a','t','a' DWORD dwDataSize; }; //cpp文件解析WAVE文件: QFile file("test.wav"); if (file.open(QIODevice::ReadOnly)) { RIFF_HEADER riff = {0}; FMT_BLOCK fmt = {0}; DATA_BLOCK dataBlock = {0}; file.read((char*)&riff, sizeof(RIFF_HEADER)); file.read((char*)&fmt, sizeof(FMT_BLOCK)); if (fmt.dwFmtSize == 0x00000012) { char szTemp[2]; file.read(szTemp, 2); } else if (fmt.dwFmtSize == 0x00000010) { } file.read((char*)&dataBlock, sizeof(DATA_BLOCK)); file.close(); int nSeconds = (dataBlock.dwDataSize / (fmt.wavFormat.nChannels * fmt.wavFormat.nSamplesPerSec * fmt.wavFormat.wBitsPerSample / 8)); 4650080/(2*44100*16/8)= 4650080/176400 参考内容及补充说明: wav文件包括头和数据两部分,其结构如下:(从文件头开始依次排列) 1)首先是字符串“RIFF” ,占4个字节。 2)波形块的大小:DWORD,占4字节。波形块的大小=(文件大小-8) 3)字符串"WAVE",占4个字节。 4)字符串“fmt ”,占4个字节,注意fmt后有个空格字符(0x20)。 5)格式块的大小,DWORD,占4个字节 6)格式块,VC中用WAVEFORMATEX结构体描述,占18个字节,可用sizeof(WAVEFORMATEX)计算。 其中WAVEFORMATEX结构体的定义为:(更详细的描述可以参考msdn) typedef struct tWAVEFORMATEX { WORD wFormatTag; /* format type */ WORD nChannels; /* number of channels (i.e. mono, stereo...) */ DWORD nSamplesPerSec; /* sample rate */ DWORD nAvgBytesPerSec; /* for buffer estimation */ WORD nBlockAlign; /* block size of data */ WORD wBitsPerSample; /* number of bits per sample of mono data */ WORD cbSize; /* the count in bytes of the size of */ /* extra information (after cbSize) */ } WAVEFORMATEX, *PWAVEFORMATEX, NEAR *NPWAVEFORMATEX, FAR *LPWAVEFORMATEX; 7)字符串"data",占4个字节。 8)波形数据的大小,DWORD,占4个字节。 9)声音数据,大小在8)中描述。 以下是一个波形文件样本的头部: 00000000h: 52 49 46 46 E6 E4 05 00 57 41 56 45 66 6D 74 20 ; RIFF驿..WAVEfmt 00000010h: 12 00 00 00 01 00 01 00 40 1F 00 00 80 3E 00 00 ; ........@...?>.. 00000020h: 02 00 10 00 00 00 64 61 74 61 C0 E4 05 00 ; ......data冷.. 从该样本可以看出: 该波形文件波形块的大小为386278(0x0005E4E6),波形文件大小为:386278+8 =386286 字节; 格式块的大小(WAVEFORMATEX结构体)为18字节; (有的为16字节,也即从地址 10h开始是10 00 00 00 ) 波形数据的大小为386240字节(0x0005E4C0); 格式块(WAVEFORMATEX结构体)中定义的声音数据属性为: wFormatTag,0x0001 即WAVE_FORMAT_PCM ; nChannels , 0x0001 即单声道; nSamplesPerSec , 0x00001F40 即采样率8000Hz; nAvgBytesPerSec , 0x00003E80 即平均字节速率16000字节(16bit量化),可以根据 该数据估计缓冲区的大小; nBlockAlign , 0x0002 即块联合为2字节(16bit量化,2字节表示一个采样点,播放时 必须从以块为单位从块头开始播放); wBitsPerSample , 0x0010 即每个采样点的比特值为16(16bit量化)。nBlockAlign值即 由该值除以8计算出来; cbSize是可选的,当WAVEFORMATEX为16字节时没有这两个字节,当是18字节时有 该两个字节,一般都填0x0000。 计算播放时间:读文件头时读出WAVEFORMATEX,该结构的nAvgBytesPerSec表示每秒 平均的字节数, 该值也可以这么计算 nAvgBytesPerSec = nChannels * nSamplesPerSec * wBitsPerSample / 8; 在这个结构后面紧跟"data"(就是0x6461 7461),在后面先是数据大小,然后是具体数据. 用这个数据大小除以nAvgBytesPerSec既得文件的播放时间。 注:有的地方说wBitsPerSample / 8 其实就是nBlockAlign 的大小,经实验证明这两个 值不一定相等。 基于Visual C++6.0的声音文件操作 一、前言 当前Visual C++相关的编程资料中,无论是大部头的参考书,还是一些计算机杂志,对声音文件的处理都是泛泛的涉及一下,许多编程爱好者都感到对该部分的内容了解不是很透彻,本文希望能够给刚刚涉及到声音处理领域的朋友们起到一个引路的作用,帮助他们尽快进入声音处理的更深奥空间。 当前计算机系统处理声音文件有两种办法:一是使用现成的软件,如微软的录音机、SoundForge、CoolEdit等软件可以实现对声音信号进行录音、编辑、播放的处理,但它们的功能是有限的,为了更灵活,更大限度地处理声音数据,就不得不使用另外一种方法,既利用微软提供的多媒体服务,在Windows环境下自己编写程序来进行声音处理来实现一些特定的功能。下面就开始介绍声音文件的格式和在Windows环境下使用Visual C++开发工具进行声音文件编程处理的方法,本文所有的程序代码都在Windows2000、Visual C++6.0环境下编译通过,运行正常。 二、RIFF文件结构和WAVE文件格式 Windows支持两种RIFF(Resource Interchange File Format,"资源交互文件格式")格式的音频文件:MIDI的RMID文件和波形音频文件格式WAVE文件,其中在计算机领域最常用的数字化声音文件格式是后者,它是微软专门为Windows系统定义的波形文件格式(Waveform Audio),由于其扩展名为"*.wav",因而该类文件也被称为WAVE文件。为了突出重点,有的放矢,本文涉及到的声音文件所指的就是WAVE文件。常见的WAVE语音文件主要有两种,分别对应于单声道(11.025KHz采样率、8Bit的采样值)和双声道(44.1KHz采样率、16Bit的采样值)。这里的采样率是指声音信号在进行"模?数"转换过程中单位时间内采样的次数。采样值是指每一次采样周期内声音模拟信号的积分值。对于单声道声音文件,采样数据为八位的短整数(short int 00H-FFH);而对于双声道立体声声音文件,每次采样数据为一个16位的整数(int),高八位和低八位分别代表左右两个声道。WAVE文件数据块包含以脉冲编码调制(PCM)格式表示的样本。在进行声音编程处理以前,首先让我们来了解一下RIFF文件和WAVE文件格式。 RIFF文件结构可以看作是树状结构,其基本构成是称为"块"(Chunk)的单元,每个块有"标志符"、"数据大小"及"数据"所组成,块的结构如图1所示: 块的标志符(4BYTES) 数据大小 (4BYTES) 数据 图一、 块的结构示意图 从上图可以看出,其中"标志符"为4个字符所组成的代码,如"RIFF","LIST"等,指定块的标志ID;数据大小用来指定块的数据域大小,它的尺寸也为4个字符;数据用来描述具体的声音信号,它可以由若干个子块构成,一般情况下块与块是平行的,不能相互嵌套,但是有两种类型的块可以嵌套子块,他们是"RIFF"或"LIST"标志的块,其中RIFF块的级别最高,它可以包括LIST块。另外,RIFF块和LIST块与其他块不同,RIFF块的数据总是以一个指定文件中数据存储格式的四个字符码(称为格式类型)开始,如WAVE文件有一个"WAVE"的格式类型。LIST块的数据总是以一个指定列表内容的4个字符码(称为列表类型)开始,例如扩展名为".AVI"的视频文件就有一个"strl"的列表类型。RIFF和LIST的块结构如下: RIFF/LIST标志符 数据1大小 格式/列表类型 数据1 数据 图二、RIFF/LIST块结构 WAVE文件是非常简单的一种RIFF文件,它的格式类型为"WAVE"。RIFF块包含两个子块,这两个子块的ID分别是"fmt"和"data",其中"fmt"子块由结构PCMWAVEFORMAT所组成,其子块的大小就是sizeofof(PCMWAVEFORMAT),数据组成就是PCMWAVEFORMAT结构中的数据。WAVE文件的结构如下图三所示: 标志符(RIFF) 数据大小 格式类型("WAVE") "fmt" Sizeof(PCMWAVEFORMAT) PCMWAVEFORMAT "data" 声音数据大小 声音数据 图三、WAVE文件结构图 PCMWAVEFORMAT结构定义如下: Typedef struct { WAVEFORMAT wf;//波形格式; WORD wBitsPerSample;//WAVE文件的采样大小; }PCMWAVEFORMAT; WAVEFORMAT结构定义如下: typedef struct { WORD wFormatag;//编码格式,包括WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM等 WORD nChannls;//声道数,单声道为1,双声道为2; DWORD nSamplesPerSec;//采样频率; DWORD nAvgBytesperSec;//每秒的数据量; WORD nBlockAlign;//块对齐; }WAVEFORMAT; "data"子块包含WAVE文件的数字化波形声音数据,其存放格式依赖于"fmt"子块中wFormatTag成员指定的格式种类,在多声道WAVE 文件中,样本是交替出现的。如16bit的单声道WAVE文件和双声道WAVE文件的数据采样格式分别如图四所示: 16位单声道: 16位单声道: 采样一 采样二 …… 低字节 高字节 低字节 高字节 …… 16位双声道: 采样一 …… 左声道 右声道 …… 低字节 高字节 低字节 高字节 图四、WAVE文件数据采样格式 三、声音文件的声音数据的读取操作 操作声音文件,也就是将WAVE文件打开,获取其中的声音数据,根据所需要的声音数据处理算法,进行相应的数学运算,然后将结果重新存储与WAVE格式的文件中去。可以使用CFILE类来实现读取操作,也可以使用另外一种方法,拿就是使用Windows提供的多媒体处理函数(这些函数都以mmino打头)。这里就介绍如何使用这些相关的函数来获取声音文件的数据,至于如何进行处理,那要根据你的目的来选择不同的算法了。WAVE文件的操作流程如下: 1(调用mminoOpen函数来打开WAVE文件,获取HMMIO类型的文件句柄; 2(根据WAVE文件的结构,调用mmioRead、mmioWrite和mmioSeek函数实现文件的读、写和定位操作; 3(调用mmioClose函数来关闭WAVE文件。 下面的函数代码就是根据WAVE文件的格式,实现了读取双声道立体声数据,但是在使用下面的代码过程中,注意需要在程序中链接Winmm.lib库,并且包含头文件"Mmsystem.h"。 BYTE * GetData(Cstring *pString) //获取声音文件数据的函数,pString参数指向要打开的声音文件; { if (pString==NULL) return NULL; HMMIO file1;//定义HMMIO文件句柄; file1=mmioOpen((LPSTR)pString,NULL,MMIO_READWRITE);//以读写模式打开所给的WAVE文件; if(file1==NULL) { MessageBox("WAVE文件打开失败~"); Return NULL; } char style[4];//定义一个四字节的数据,用来存放文件的类型; mmioSeek(file1,8,SEEK_SET);//定位到WAVE文件的类型位置 mmioRead(file1,style,4); if(style[0]!='W'||style[1]!='A'||style[2]!='V'||style[3]!='E')//判断该文件是否为"WAVE"文件格式 { MessageBox("该文件不是WAVE格式的文件~"); Return NULL; } PCMWAVEFORMAT format; //定义PCMWAVEFORMAT结构对象,用来判断WAVE文件格式; mmioSeek(file1,20,SEEK_SET); //对打开的文件进行定位,此时指向WAVE文件的PCMWAVEFORMAT结构的数据; mmioRead(file1,(char*)&format,sizeof(PCMWAVEFORMAT));//获取该结构的数据; if(format.wf.nChannels!=2)//判断是否是立体声声音; { MessageBox("该声音文件不是双通道立体声文件"); return NULL; } mmioSeek(file1,24+sizeof(PCMWAVEFORMAT),SEEK_SET); //获取WAVE文件的声音数据的大小; long size; mmioRead(file1,(char*)&size,4); BYTE *pData; pData=(BYTE*)new char[size];//根据数据的大小申请缓冲区; mmioSeek(file1,28+sizeof(PCMWAVEFORMAT),SEEK_SET);//对文件重新定位; mmioRead(file1,(char*)pData,size);//读取声音数据; mmioClose(file1, MMIO_FHOPEN);//关闭WAVE文件; return pData; } 四、使用MCI方法操作声音文件 WAVE声音文件一个最基本的操作就是将文件中的声音数据播放出来,用Windows提供的API函数BOOL sndPlaySound(LPCSTR lpszSound, UINT fuSound)可以实现小型WAV文件的播放,其中参数lpszSound 为所要播放的声音文件,fuSound为播放声音文件时所用的标志位。例如实现Sound.wav 文件的异步播放,只要调用函数sndPlaySound("c:\windows\Sound.wav",SND_ASYNC)就可以了,由此可以看到sndPlaySound函数使用是很简单的。但是当WAVE文件大于100K时,这时候系统无法将声音数据一次性的读入内存,sndPlaySound函数就不能进行播放了。为了解决这个问题,你的一个选择就是用MCI方法来操作声音文件了。在使用MCI方法之前,首先需要在你开发的项目设置Project->Setting->Link->Object/library modules中加入winmm.lib。并在头文件中包括"mmsystem.h"头文件。 MicroSoft API提供了MCI(The Media Control Interface)的方法mciSendCommand()和mciSendString()来完成WAVE文件的播放,这里仅介绍mciSendCommand()函数的使用。 原型:DWORD mciSendCommand(UINT wDeviceID,UINT wMessage,DWORD dwParam1,DWORD dwParam2); 参数:wDeviceID:接受消息的设备ID; Message:MCI命令消息; wParam1:命令的标志位; wParam2:所使用参数块的指针 返值:调用成功,返回零;否则,返回双字中的低字存放有错误信息。 在使用MCI播放声音文件时,首先要打开音频设备,为此要定义MCI_OPEN_PARMS变量 OpenParms,并设置该结构的相应分量: OpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_WAVEFORM_AUDIO;//WAVE类型 OpenParms.lpstrElementName = (LPCSTR) Filename;//打开的声音文件名; OpenParms.wDeviceID = 0;//打开的音频设备的ID mciSendCommand (NULL, MCI_OPEN,MCI_WAIT | MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID | MCI_OPEN_ELEMENT, (DWORD)(LPVOID) &OpenParms)函数调用发送MCI_OPEN命令后,返回的参数 OpenParms中成员变量的wDeviceID指明打开了哪个设备。需要关闭音频设备时只要调用mciSendCommand (m_wDeviceID, MCI_CLOSE, NULL, NULL)就可以了。 播放WAVE文件时,需要定义MCI_PLAY_PARMS变量PlayParms,对该变量进行如下设置:PlayParms.dwFrom = 0,这是为了指定从什么地方(时间)播放WAVE文件,设置好以后,调用函数mciSendCommand (m_wDeviceID, MCI_PLAY,MCI_FROM, (DWOR D)(LPVOID)&PlayParms));就实现了WAVE声音文件的播放。 另外,调用mciSendCommand (m_wDeviceID, MCI_PAUSE, 0,(DWORD)(LPVOID)&PlayParms)实现了暂停功能。调用mciSendCommand (m_wDeviceID, MCI_STOP, NULL, NULL)实现停止功能等,可以看出,这些不同的功能实现都是依靠参数"Message"取不同的值来实现的。 不同的Message和dwParam1、dwParam2的组合还可以实现文件的 跳跃功能。如下面的代码实现了跳转到WAVE文件末端的操作:mciSendCommand (m_wDeviceID, MCI_SEEK, MCI_SEEK_TO_END, NULL)。 下面的代码实现了WAVE声音文件的播放: void CTest1View::OnMciPlayWave() { // TODO: Add your command handler code here MCI_OPEN_PARMS mciOpenParms; MCI_PLAY_PARMS PlayParms; mciOpenParms.dwCallback=0; mciOpenParms.lpstrElementName="d:\\chimes.wav"; mciOpenParms.wDeviceID=0; mciOpenParms.lpstrDeviceType="waveaudio"; mciOpenParms.lpstrAlias=" "; PlayParms.dwCallback=0; PlayParms.dwTo=0; PlayParms.dwFrom=0; mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE|MCI_OPEN_ELEMENT,(DWORD)(LPVOID)&mciOpenParms);//打开音频设备; mciSendCommand(mciOpenParms.wDeviceID,MCI_PLAY,MCI_WAIT,(DWORD)(LPVOID)&PlayParms);//播放WAVE声音文件; mciSendCommand(mciOpenParms.wDeviceID,MCI_CLOSE,NULL,NULL);//关闭音频设备; } 五、DirectSound操作WAVE文件的方法 MCI虽然调用简单,功能强大,可以满足声音文件处理的基本需要,但是MCI也有它的缺点,那就是它一次只能播放一个WAVE文件,有时在实际应用中,为了实现混音效果,需要同时播放两个或两个以上的WAVE文件时,就需要使用微软DirectX技术中的DirectSound了,该技术直接操作底层声卡设备,可以实现八个以上WAV文件的同时播放。 实现DirectSound需要以下几个步骤:1.创建及初始化DirectSound;2.设定应用程序的声音设备优先级别方式,一般为DSSCL_NORMAL;2. 将WAV文件读入内存,找到格式块、数据块位置及数据长度;3.创建声音缓冲区;4.载入声音数据;5.播放及停止: 下面的函数利用DirectSound技术实现了一个WAVE声音文件的播放(注意项目设置中要包含"dsound.lib、dxguid.lib"的内容),代码和注释如下: void CPlaysoundView::OnPlaySound() { // TODO: Add your command handler code here LPVOID lpPtr1;//指针1; LPVOID lpPtr2;//指针2; HRESULT hResult; DWORD dwLen1,dwLen2; LPVOID m_pMemory;//内存指针; LPWAVEFORMATEX m_pFormat;//LPWAVEFORMATEX变量; LPVOID m_pData;//指向语音数据块的指针; DWORD m_dwSize;//WAVE文件中语音数据块的长度; CFile File;//Cfile对象; DWORD dwSize;//存放WAV文件长度; //打开sound.wav文件; if (!File.Open ("d://sound.wav", CFile::modeRead |CFile::shareDenyNone)) return ; dwSize = File.Seek (0, CFile::end);//获取WAVE文件长度; File.Seek (0, CFile::begin);//定位到打开的WAVE文件头; //为m_pMemory分配内存,类型为LPVOID,用来存放WAVE文件中的数据; m_pMemory = GlobalAlloc (GMEM_FIXED, dwSize); if (File.ReadHuge (m_pMemory, dwSize) != dwSize)//读取文件中的数据; { File.Close (); return ; } File.Close (); LPDWORD pdw,pdwEnd; DWORD dwRiff,dwType, dwLength; if (m_pFormat) //格式块指针 m_pFormat = NULL; if (m_pData) //数据块指针,类型:LPBYTE m_pData = NULL; if (m_dwSize) //数据长度,类型:DWORD m_dwSize = 0; pdw = (DWORD *) m_pMemory; dwRiff = *pdw++; dwLength = *pdw++; dwType = *pdw++; if (dwRiff != mmioFOURCC ('R', 'I', 'F', 'F')) return ;//判断文件头是否为"RIFF"字符; if (dwType != mmioFOURCC ('W', 'A', 'V', 'E')) return ;//判断文件格式是否为"WAVE"; //寻找格式块,数据块位置及数据长度 pdwEnd = (DWORD *)((BYTE *) m_pMemory+dwLength -4); bool m_bend=false; while ((pdw < pdwEnd)&&(!m_bend)) //pdw文件没有指到文件末尾并且没有获取到声音数据时继续; { dwType = *pdw++; dwLength = *pdw++; switch (dwType) { case mmioFOURCC('f', 'm', 't', ' ')://如果为"fmt"标志; if (!m_pFormat)//获取LPWAVEFORMATEX结构数据; { if (dwLength < sizeof (WAVEFORMAT)) return ; m_pFormat = (LPWAVEFORMATEX) pdw; } break; case mmioFOURCC('d', 'a', 't', 'a')://如果为"data"标志; if (!m_pData || !m_dwSize) { m_pData = (LPBYTE) pdw;//得到指向声音数据块的指针; m_dwSize = dwLength;//获取声音数据块的长度; if (m_pFormat) m_bend=TRUE; } break; } pdw = (DWORD *)((BYTE *) pdw + ((dwLength + 1)&~1));//修改pdw指针,继续循环; } DSBUFFERDESC BufferDesc;//定义DSUBUFFERDESC结构对象; memset (&BufferDesc, 0, sizeof (BufferDesc)); BufferDesc.lpwfxFormat = (LPWAVEFORMATEX)m_pFormat; BufferDesc.dwSize = sizeof (DSBUFFERDESC); BufferDesc.dwBufferBytes = m_dwSize; BufferDesc.dwFlags = 0; HRESULT hRes; LPDIRECTSOUND m_lpDirectSound; hRes = ::DirectSoundCreate(0, &m_lpDirectSound, 0);//创建DirectSound对象; if( hRes != DS_OK ) return; m_lpDirectSound->SetCooperativeLevel(this->GetSafeHwnd(), DSSCL_NORMAL); //设置声音设备优先级别为"NORMAL"; //创建声音数据缓冲; LPDIRECTSOUNDBUFFER m_pDSoundBuffer; if (m_lpDirectSound->CreateSoundBuffer (&BufferDesc, &m_pDSoundBuffer, 0) == DS_OK) //载入声音数据,这里使用两个指针lpPtr1,lpPtr2来指向DirectSoundBuffer缓冲区的数据,这是为了处理大型WAVE文件而设计的。dwLen1,dwLen2分别对应这两个指 针所指向的缓冲区的长度。 hResult=m_pDSoundBuffer->Lock(0,m_dwSize,&lpPtr1,&dwLen1,&lpPtr2,&dwLen2,0); if (hResult == DS_OK) { memcpy (lpPtr1, m_pData, dwLen1); if(dwLen2>0) { BYTE *m_pData1=(BYTE*)m_pData+dwLen1; m_pData=(void *)m_pData1; memcpy(lpPtr2,m_pData, dwLen2); } m_pDSoundBuffer->Unlock (lpPtr1, dwLen1, lpPtr2, dwLen2); } DWORD dwFlags = 0; m_pDSoundBuffer->Play (0, 0, dwFlags); //播放WAVE声音数据; } 为了更好的说明DiretSound编程的实现,笔者使用了一个函数来实现所有的操作,当然读者可以将上面的内容包装到一个类中,从而更好的实现程序的封装性,至于如何实现就不需要笔者多说了,真不明白的话,找本C++的书看看。如果定义了类,那么就可以一次声明多个对象来实现多个WAVE声音文件的混合播放。也许细心的读者会发现,在介绍WAVE文件格式的时候我们介绍了PCMWAVEFORMAT结构,但是在代码的实现读取WAVE文件数据部分,我们使用的却是LPWAVEFORMATEX结构,那末是不是我们有错误呢,其实没有错,对于PCM格式的WAVE文件来说,这两个结构是完全一样的,使用LPWAVEFORMATEX结构不过是为了方便设置DSBUFFERDESC对象罢了。 操作WAVE声音文件的方法很多,灵活的运用它们可以灵活地操作WAVE文件,这些函数的详细用途读者可以参考MSDN。本文只是对WAVE文件的操作作了一个肤浅的介绍,希望可以对读者起到抛砖引玉的作用。 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 电力安全月工作总结 [电力安全月工作总结]电力安全月工作总结 2011年3月1日至3月31日为我公司的安全生产月,**变电站围绕;夯实基储提高素质、树立标杆、争创一流;的主题,开展了丰富多彩、形式多样的具体行动:通过看板形式宣传安全第一、预防为主的方针,通过48+4的学习机会,进行安全生产大讨论,通过安全活动进行查找本站的隐患的活动,电力安全月工作总结。形成了;人人学会安全,层层尽责保证安全;的 良好氛围,使我站的安全生产工作又上了一个新的台阶。 本站安全生产月活动具体工作如下: 1.开展安全月活动宣传工作,大家坐在一起讨论活动的主题、学习实施纲要、讨论各个实施阶段的活动安排。深刻反思11.3事故,汲取事故教训,每人写了一份11.3事故反思,并对本站的安全管理、记录报表、规章制度、培训工作、事故隐患每个值班员都谈了自己的看法和建议,对站内管理每个人都倾注了最大的热情,可见11.3对每一个值班员的触动是刻骨铭心的,安全月的必要开展对变电站各项工作的 促进,尤其对值班员安全意识、主人翁精神的影响最为深刻。 2.深入开展安全生产大检查活动。在安全生产整顿周活动的基础上,结合秋季安全大检查,进一步查摆了本站安全生产的隐患,特别是各种规章制度的建立、健全、完善和执行情况,对现场运行规程从全面、具体和针对性上进行了修订,制定全站停电的反事故预案,制定低温天气和防冰闪的反事故措施,进行现场演练。当前正处年底收 45 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 关和人员调整后的敏感时期,人员思想浮动大,而且本站正在进行新母差与新间隔投运的准备工作,施工人员多,施工人员安全意识和安全防范技能较低,是近阶段我站安全运行的一大隐患,我们会同工作负责人一起讨论施工过程中的存在和潜在的危害,并有针对性地制定防范了措施,保证了施工安全的进行。针对人员素质参差不起,安全意识高低不同,我们制定了《**站考核》,制定措施, 明确职责和 工作程序,对任何可能发生的情况做了充分的准备工作。 3.利用交接-班的时间,我们查找本站存在的隐患,实行分片分区,责任到人,对查找到的隐患汇总分析,能自己解决的我们都及时认真地消除,对我站能力不足不能解决的,我们纳入工区的职业安全健康体系,由工区负责解决,工作总结《电力安全月工作总结》。该报缺陷的上报缺陷,该报危害辨识的报危害辨识,使站内所有设备、所有 工作、所有危险点在控、可控、能控。 4.对在本月进行的工作、操作等,我们编制事故预案,如220KV母差保护更换的准备工作和悬垂刷涂工作, 除了工区安排跟踪外,站内根据人员新调整、新人员对设备不熟悉的现状,三班改为两班,加强值班力量, 保证了各项工作的顺利完成。为防止意外发生,我 们共同讨论制定出了在工作期间母线故障的反事故预案。 5.每个班利用晚饭后的时间讨论检查了我站在遵章守制方面还存在哪些差距,现有规程制度能否满足现场规范化、标准化工作需要,并在站内宣读并实施了《**站考核细则》,按照个人能力分为12大员管理站内事务,规定每个值班员必须按照规章制度工作,否则就严格 46 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 考核。在个人专业技能与岗位要求存在的差距,站内按人所需制订培训,建立心智加油站和个人提升计划的培训平台进行培训。工作日志、检修记录、安全活动、安全用具记录、缺陷记录等班组记录已 经和工区进行交流,完善纪录格式。 6.对全站值班员进行《电力安全工作规程》、本岗位安全职责、工作中的危险点辨识和防范措施及相关专业的规程制度等的培训,选派两名值班员参加工区举办的安规比赛,锻炼值班员具备工作所要求的 安全生产技能,熟知各项工作的危险点及防范措施, 7.完善三票,针对本站实际按照运行工区职业安全健康管理体系实施;三票;管理制度,内容完善,;三票;按照规定执行,严格执行倒闸操作;六关;制度,操作准备关、接令关、操作票填写关、核对图板关、操作监护关、质量检查关,,;三票;的填写及执行情况良好。;三票;管理制度健全,制定了;三票;合格标准和考核规定,;三票;合格评价符合标准要求,对发现的问题能及时提出改进措施,有记录 可查,定期对;三票;的执行情况进行统计、分析和考评。 8.重温《沧州供电公司运行管理标准》及运行相关管理规定。完善我站的《综自站的管理规定》,并制定措施严格执行。查找五防系统管理和软件缺陷,及时上报,并请厂家销缺。查找现场防误闭锁装臵的运行情况,缺陷及时报告,建立起完善解锁钥匙的管理制度,严格执行,严格执行操作监护制度,重新修改操作密码,严格密码管理, 使操作监护制度的执行从小操作就具备条件。 9.对继电保护及自动装臵进行全面检查,核对保护装臵定值与定值 47 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 单相符。规定每月20日核对保护压板投切正确,并要求做好记录。检查户外继电器、端子箱等二次设备有防雨、防潮和保护室降温等安 全措施。 10.现场安全措施方面进行有针对性制定现场三项措施和进行危险点分析,现场作全封闭围网,现场措施落实良好,对每个作业现场做到层层把关,严格执行;三大措施;,做到责任到位、工作到位、监督到位,对任何违反安全规程的行为立即得到制止。 11.强调安全用具的管理。各类安全用具配臵、台账、试验、存放使用符合要求,增加 每月10日对安全器具进行试验检查,使其保持在完好状态。 12.完善消防管理。重新完善消防管理制度,健全消防组织,使新来的值班员在消防组织中找到自己的定位,明确各自的职责,消防设施、器具齐全,布臵符合规定,状态完好,培训职工消防器材的使用 方法。 13.在日常管理中强调安全监督体系,由站长牵头组成安全监督体系,每个值班员都有安全监督责任,明确分工,履行安全监督职责,重新要求运行日志、安全分析记录和安全活动等记录的填写,使其具 有针对性和及时性, 14.加强输变电设备管理,健全输变电设备台账和技术档案,并做到及时更新。新设备技术培训工作做到及时有效,有效利用嵌入式变电设备巡检系统及按照《作业指导书》的要求,组织开展变电设备巡视检查。 ;安全生产月;活动即将结束,但安全生产是永远没有结束的,而是一个起点,一个契机,今后的工作中我们要继续发扬安全生产月 48 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 的活动精神,以人为本,从提高人员素质入手,时时保安全,处处要安全,严格按照我公司和工区的安全生产要求执行,全面落实安全责任制,使我站的安全运行再上一个新的台阶,为我公司的安全生产做 出贡献。 电力行业职称晋升业务工作总结 [电力行业职称晋升业务工作总结]我叫*,*年*月出生,现年*岁,中共党员,电力行业职称晋升业务工作总结。*年*月参加工作,先后在*、*供电站、*工程队、*修试班工作,*年考入华北电力大学(北京)用电监察与管理专业脱产学习两年,*年毕业后在*局*保线站工作,*年元月获得助理工程师职称,*年*月调至*科,先后从事*专责、*专责、*专责和*专责工作。现在*科主管*营业管理工作,同时兼任*局*专责 和*专责。 任助理工程师近*年来,自己的工作性质和从事的专业虽没有改变,但不同岗位的锻炼,使自己的专业知识有了一个更大的实践和拓展空间,进一步锻炼和丰富了自己,增长了知识和才干,提高了自己的专业技术水平,各方面都得到了长足的进步,同时,在近几年的营销管理工作实践中,自己坚持以市场为导向,以效益为中心,以服务宗旨,坚持科学管理,规范经营,狠抓落实,积极开拓电力市场,圆满完成 了各项工作任务并取得了较好成绩。 一、思想政治素质得到提高 49 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 在多年的工作实践中,自己深深认识到,只有政治上的坚定和思想上的清醒,才能保持良好的工作作风和忠于职守、爱岗敬业的勤奋精神。因此,在任助理工程师以来的工作中,自己更注重不断地补充自己,提高自己的政治和理论素养。一是抓好学习,尤其是理论学习,用正确的理论来指导工作,在学习中,自己一方面按照规定的学习制度参加集体学习,记好学习笔记和心得体会,还利用工作和业余时间抓好自学,注意拓宽学习面,提高自己的综合知识水平,并注重了解和掌握时事政治,在思想上时刻与党中央保持一致,在工作步调上与县局保持一致,同时,联系思想和工作实际,与同事们一起有针对性地学习探讨,研讨工作学习方法和体会,用正确的理论武装思想,指 导工作,不断改造自己的世界观。 二是认真贯彻党的路线、方针、政策,坚持四项基本原则,贯彻上级的指示精神,以明确的思想意识来指导自己的行动,按照上级的安排部署,积极投身于各种活动。三是在工作学习中认真实践全心全意为人民服务的宗旨,牢固树立公仆意识。自己经常想,我之所以能从一个普通工人走上管理岗位,取得专业技术职称,完全是党的培养和领导的信任,在这个岗位上我只能是尽职尽责,干好工作回报党。因此,在日常工作中,自己坚持深入基层,到一线调查了解管理中存在的问题,进一步改进工作,提高自己能力,同时,对自己严格要求,减少办事程序,提高工作效能,恪守职业道德,注重保持良好的职业形象,工作总结《电力行业职称晋升业务工作总结》。四是坚持党性原则,实事求是,作风正派,用自己的行动去体现一个党员和工程技 50 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 术人员的导向作用,发扬敢抓敢管的作用,推动自己主管的各项工作不断发展。同时,在日常工作中,自己坚持努力做到踏踏实实工作,堂堂正正做人,正确对待个人的名利待遇,坚持扎实认真、兢兢业业、 尽职尽责地努力工作,圆满完成各项工作任务。 二、技术和业务水平不断增强 从参加工作尤其是任助理工程理师职称以来,自己的技术水平和业务能力得到很大的提高和加强,如果说两年的专业技术学习奠定了自己的理论基础,那么,多年的工作实践更使这些理论得以巩固和提高。在工作实践中,自己常常认识到自己专业理论还比较薄弱,因此,自己不断加强学习,虚心请教有专业特长的工程师和学者,不放过每一个学习和提高的机会,使自己的技术水平和能力不断加强。在学习和工作实践中,自己一是侧重学习,加强理论功底的培养。每到业余时间,每到夜晚,自己总是坚持看相关专业技术理论书籍,坚持记学习笔记。二是继续接受高等教育。在坚持自学的基础上,于*年至*年函授读完了华北电力大学电气工程及其自动化专业专升本学习,顺利毕 业,成为全班70人中仅有10人获得学士学位的人员之一。 这一切,更进一步奠定了自己在参与企业管理中能够较好地完成任务的基础。三是带着工作实践中的问题,有重点地学习。自己所主管的工作具有很强的专业性和技术性,如*管理、*管理等方面,有实际工作中均有比较复杂的问题需要自己拿出初步方案意见供领导决策。对此,自己一方面认真倾听各方面的意见并以自己的理论知识来加以分析,另一方面,带着这些问题查阅有关书籍资料,寻找解决问题的 51 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 方法,这些经历,使自己的理论知识和实践经验不断丰富、提高。四是订阅各种学习资料,不断研究了解国内外的先进技术和管理知识。对一些先进的理论,做到学通弄懂,对一些先进的技术和管理知识,做到与本单位的实际相结合并正确地运用到实际中去,同时,利用自己的计算机特长,熟练的掌握了用电营销管理软件的使用和日常维护以及故障的解决和排除方法,并结合实际编写操作手册,指导培训基层同志熟练操作,同时,实现了通过微机来检查和辅助决策全局的营 销状况和相关工作。 通过几年来理论与实践相结合的学习,自己的业务技术和专业知识得到很大的提高,并能有效地将理论知识应用到管理实践,取得了较 好的成效。 三、工作业务卓有成效 1、连年完成各项经营指标。在自己任职的近几年时间里,经历了电力市场由买方变为卖方的转型期。在此期间,自己发挥自己的专业所长,为全局的经营指标完成而尽职尽责。尤其是在近年来,自己与局领导及其他营销人员认真分析市场,贯彻上级的营销方略,千方百计开拓电力市场,并不断完善用电营业抄、核、收制度,规范经营行为,连年完成了上级下达的各项经营指标。使售电量由*年的*亿千瓦时增长到*年的*亿千瓦时,增长率*%,销售收入由*年*万元增长到*年的万元,增长率%,线损率稳中有降,综合线损较*年的*%下降到*年的*%,各项经营指标的年增长率平均以12%的速度递增。*年*月自己接管*营业主管工作后,各项经营成果不断扩大,今年1-6月,实现*收 52 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 入较去年同期增长*万元的好成绩,指标完成连创本局最好记录。 2、积极开拓电力市场。根据我县的电力市场现状,在市场营销中,自己主动出击,先后争取了原由*供电局供电的用电大户玻璃纤维厂的供电,帮助县水泥厂、*水泥厂实现了技改扩容,积极争取英特利果蔬公司等工业大户由我局供电,这一切,为我局电量增长、利润增 加和电费回收奠定了坚实基础。 3、积极开展QC活动,推进企业管理创新。从*年至今,自己连年主持参加县局QC活动,并连年获奖。*年的"降低电能表故障率"获得*局二等奖,*省电力行业协会三等奖,并被*省科协,共青团*省委授予优秀奖,*年的"降低配电变压器故障率"获得*局三等奖,*省电力行业协会优秀奖,*年的"解决10KV高压计量箱带电操作安全问题"获得*局二等奖,*省电力行业协会优秀奖。这些成果的取得,都源于自己平时的专业知识积累和调查研究的 结果。 共2页: 上一页 1 2 下一页 电力安全生产工作 [电力安全生产工作]电力安全生产工作2011年3月1日至3月31日 53 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 为我公司的安全生产月,**变电站围绕;夯实基储提高素质、树立标杆、争创一流;的主题,开展了丰富多彩、形式多样的具体行动:通过看板形式宣传安全第一、预防为主的方针,通过48+4的学习机会,进行安全生产大讨论,通过安全活动进行查找本站的隐患的活动,电力安全生产工作。形成了;人人学会安全,层层尽责保证安全;的良好氛 围,使我站的安全生产工作又上了一个新的台阶。 本站安全生产月活动具体工作如下: 1.开展安全月活动宣传工作,大家坐在一起讨论活动的主题、学习实施纲要、讨论各个实施阶段的活动安排。深刻反思11.3事故,汲取事故教训,每人写了一份11.3事故反思,并对本站的安全管理、记录报表、规章制度、培训工作、事故隐患每个值班员都谈了自己的看法和建议,对站内管理每个人都倾注了最大的热情,可见11.3对每一个值班员的触动是刻骨铭心的,安全月的必要开展对变电站各项工作的 促进,尤其对值班员安全意识、主人翁精神的影响最为深刻。 2.深入开展安全生产大检查活动。在安全生产整顿周活动的基础上,结合秋季安全大检查,进一步查摆了本站安全生产的隐患,特别是各种规章制度的建立、健全、完善和执行情况,对现场运行规程从全面、具体和针对性上进行了修订,制定全站停电的反事故预案,制定低温天气和防冰闪的反事故措施,进行现场演练。当前正处年底收关和人员调整后的敏感时期,人员思想浮动大,而且本站正在进行新母差与新间隔投运的准备工作,施工人员多,施工人员安全意识和安全防范技能较低,是近阶段我站安全运行的一大隐患,我们会同工作 54 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 负责人一起讨论施工过程中的存在和潜在的危害,并有针对性地制定防范了措施,保证了施工安全的进行。针对人员素质参差不起,安全意识高低不同,我们制定了《**站考核细则》,制定措施, 明确职责和 工作程序,对任何可能发生的情况做了充分的准备工作。 3.利用交接-班的时间,我们查找本站存在的隐患,实行分片分区,责任到人,对查找到的隐患汇总分析,能自己解决的我们都及时认真地消除,对我站能力不足不能解决的,我们纳入工区的职业安全健康体系,由工区负责解决,工作总结《电力安全生产工作》。该报缺陷的上报缺陷,该报危害辨识的报危害辨识,使站内所有设备、所有工 作、所有危险点在控、可控、能控。 4.对在本月进行的工作、操作等,我们编制事故预案,如220KV母差保护更换的准备工作和悬垂刷涂工作, 除了工区安排跟踪外,站内根据人员新调整、新人员对设备不熟悉的现状,三班改为两班,加强值班力量, 保证了各项工作的顺利完成。为防止意外发生,我 们共同讨论制定出了在工作期间母线故障的反事故预案。 5.每个班利用晚饭后的时间讨论检查了我站在遵章守制方面还存在哪些差距,现有规程制度能否满足现场规范化、标准化工作需要,并在站内宣读并实施了《**站考核细则》,按照个人能力分为12大员管理站内事务,规定每个值班员必须按照规章制度工作,否则就严格考核。在个人专业技能与岗位要求存在的差距,站内按人所需制订培训计划,建立心智加油站和个人提升计划的培训平台进行培训。工作日志、检修记录、安全活动、安全用具记录、缺陷记录等班组记录已 55 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 经和工区进行交流,完善纪录格式。 6.对全站值班员进行《电力安全工作规程》、本岗位安全职责、工作中的危险点辨识和防范措施及相关专业的规程制度等的培训,选派两名值班员参加工区举办的安规比赛,锻炼值班员具备工作所要求的 安全生产技能,熟知各项工作的危险点及防范措施, 7.完善三票管理制度,针对本站实际按照运行工区职业安全健康管理体系实施;三票;管理制度,内容完善,;三票;按照规定执行,严格执行倒闸操作;六关;制度,操作准备关、接令关、操作票填写关、核对图板关、操作监护关、质量检查关,,;三票;的填写及执行情况良好。;三票;管理制度健全,制定了;三票;合格评价标准和考核规定,;三票;合格评价符合标准要求,对发现的问题能及时提出改进措施,有记录 可查,定期对;三票;的执行情况进行统计、分析和考评。 8.重温《沧州供电公司运行管理标准》及运行相关管理规定。完善我站的《综自站的管理规定》,并制定措施严格执行。查找五防系统管理和软件缺陷,及时上报,并请厂家销缺。查找现场防误闭锁装臵的运行情况,缺陷及时报告,建立起完善解锁钥匙的管理制度,严格执行,严格执行操作监护制度,重新修改操作密码,严格密码管理, 使操作监护制度的执行从小操作就具备条件。 9.对继电保护及自动装臵进行全面检查,核对保护装臵定值与定值单相符。规定每月20日核对保护压板投切正确,并要求做好记录。检查户外继电器、端子箱等二次设备有防雨、防潮和保护室降温等安 全措施。 56 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 10.现场安全措施方面进行有针对性制定现场三项措施和进行危险点分析,现场作全封闭围网,现场措施落实良好,对每个作业现场做到层层把关,严格执行;三大措施;,做到责任到位、工作到位、监督到位,对任何违反安全规程的行为立即得到制止。 11.强调安全用具的管理。各类安全用具配臵、台账、试验、存放使用符合要求,增加 每月10日对安全器具进行试验检查,使其保持在完好状态。 12.完善消防管理。重新完善消防管理制度,健全消防组织,使新来的值班员在消防组织中找到自己的定位,明确各自的职责,消防设施、器具齐全,布臵符合规定,状态完好,培训职工消防器材的使用 方法。 13.在日常管理中强调安全监督体系,由站长牵头组成安全监督体系,每个值班员都有安全监督责任,明确分工,履行安全监督职责,重新要求运行日志、安全分析记录和安全活动等记录的填写,使其具 有针对性和及时性, 14.加强输变电设备管理,健全输变电设备台账和技术档案,并做到及时更新。新设备技术培训工作做到及时有效,有效利用嵌入式变电设备巡检系统及按照《作业指导书》的要求,组织开展变电设备巡视检查。 ;安全生产月;活动即将结束,但安全生产是永远没有结束的,而是一个起点,一个契机,今后的工作中我们要继续发扬安全生产月的活动精神,以人为本,从提高人员素质入手,时时保安全,处处要安全,严格按照我公司和工区的安全生产要求执行,全面落实安全责任制,使我站的安全运行再上一个新的台阶,为我公司的安全生产做 57 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 出贡献。 电工工作总结 [电工工作总结]电工工作总结电工工作总结 来源:,, 发布时间:2011-03-17 电工工作总结,电工工作总结范文 在炽热的去年夏天,怀着对生活期待,揣着事业的梦想,电工工作总结。我悄然走进银海,成为银海大家庭一员。岁月年轮不停运转促使我走向成熟,我相信有汗水流过的地方就有所收获。因为年轻不足之处很了然,也因为年轻所以我没有气馁,没有灰心叹气,也不会敷衍塞责,迎难而上,全身心投入到新的工作环境中来,挑战自我,挑战新环境,挑战新的工作岗位。银海,你是我们人生指路明灯,引领 我们行程的方向。 回顾2011,我心有余悸,是我平凡的一年,也是我收获的一年。首先感谢公司领导提供一个这么的大人生舞台,使我得到学习和发展机会,同时也感谢车间领导和老师傅们对我的培育之恩,教我做人,传授技能和宝贵工作经验,使我在这安全、健康、***的土壤里吸收最宝贵的养分。现在我把这一年工作情况进行全面的总结和以今后对自 己工作上需要提高提出几点要求。 我是一名运行电工。电是银海电解铝的心脏,电是贯穿整个生产铝的动脉。保证正常供电是我们运行电工使命。安全、有效、合理、正 58 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 确使用电是我们电工的工作。电是无形的,也是无情,做为电工的我,必须掌握和熟悉《电业安全操作规程》的相关内容,比如电对人身安全距离,220KV安全距离是3m,,巡视电气设备不得靠近避雷器和避雷针,穿戴劳保品的要求等等,电业安全基础知识是电工必备的。做为运行电工,巡视工作非常重要,巡视可以发现设备运行中出现在主控室无法监视得到的问题,是在现场发现设备运行是否正常重要途径,是保证设备正常运行关键性的工作。我们运行人员在这项工作中不可走马观花、草率应付、掉以轻心去完成。在这一年工作里,我主要熟悉供电运行系统图,全厂的电气设备名称和编号、状态、位臵。在日常工作中,开、结工作票,倒闸操作,识别信号报警,监盘,事故处理,这些工作内容我都做到熟悉和掌握。经历了一年,我觉得自己还存在一些不足,对突发事故处理经验不足,电气设备工作原理,二次保护,运行设备维护,这些知识没有更深的理解。车间每周五进行技能和安全培训,事故处理经验的总结,这些有利我工作技能提升和丰富经验。今后在学习和工作过程中,我要做到,多发现问题,多问问题,多考虑问题,多讨论和解决问题。遇上难题,多向老师傅、技术员及车间领导学习,团结合作,相互学习,共同进步。遵守公司、车间劳动纪律,我会始终保持着饱满的工作热情,对待工作认真负责,任劳任怨,认真完成车间及班组所交任务。争取做个有素质、有技术、 有创新、有思想合格供电运行人员。 人与人之间有微妙的关系,我们企业是个大家庭、是个团队。同事之间和睦相处,相互尊重,相互理解,相互关心,处理好同事之间的关系, 59 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 营造一个安全、健康、***的工作环境,是我们每位员工的责任。在银海工作我感受到家的温馨 ,因为在车间里我身边每位同事都很关心和爱护我,形同手足亲如兄弟,工作上不会地方他们手把手、无一保留教会我,生活上有困难就会伸手援助我,工作总结《电工工作总结》。公司业余生活丰富多彩,安全知识竞赛、举办节日联欢晚会、技能比拼、…等等,举行这些活动让我受益非浅。记得去年举办演讲比赛,是我人生第一次上这么大的舞台,虽没能在比赛中脱颖而出,但我得到上台锻炼胆量和口才的机会。篮球比赛这是一个团队竞技,通过参加比赛后我感悟挺深刻,一个集体、一个团队的能量是无穷的,人人都能无私、团结在一起,还有什么困难不可以战胜,如果我们员工把这样的精神放在工作上,那我们银海在发展的路上还有什么事情可以去畏惧呢?举行这些活动有益同事之间交流,同事之间就能多一点理解,少一点摩擦,多一点信任,少一点猜疑,使工作环境更加***。在银海我感受爱在延伸,今年多个地区干旱受灾,我们银海人组织起来尽自己所能捐钱捐物,为灾区送真情送温暖。做为银海一员难道不为他们这样的慷慨无私而感动吗,公司的政策落实深入人心,在火热的季节,发放高温补贴,在深夜宁静的夜晚,员工上夜班备受睡眠的煎熬,发放夜班津贴,由于环境和条件的原因,员工上班离厂比较远,也发放了交通补贴,这些举措都是公司关心员工,体贴员工,提高各种待遇,处处为员工着想,这就是管理人性化的体现啊。公司管理也更规范化了,上、下班的员工排好队整齐进出厂,从这点上展现员工的精神风貌,同时也体现我们公司向更精神、更文明迈出更重要的一步。 60 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 然而经历了经济危机风暴后,在市场经济动荡冲击下,铝价回升缓慢起伏不定,电价却提高。做为主产铝锭,做为用电大户,我们要减低成本,没有退路。古人有句话,变则通,通则久。管理创新,技术创新,只有创新,只有求变我们才能发展,公司在管理也做出些变革,执行绩效工资,提出加强执行力,由于企业发展历史、人员、环境等各种因素影响下,在转变、执行、完善过程是极其艰辛和漫长。银海人应胸怀坦荡,海纳百川,敢于承认新事物诞生,消除对新事物不良抵触心理,迎接对新事物的挑战。相信在公司领导的英明领导下,银海未来发展会变得更好。军人有句话,;服从命令为天子;,我们做为银海人应该遵守纪律,服从管理,听从指挥,为我们公司管理工作上更上一台阶出自己一份微薄之力。因而我们员工思想上要转变,自觉不断充电,提高自身知识和技能,提高自身修养,调整个人来适应公司发展需要。公司提出节能减排,技术改造,而这些或许一个人贡献是微不足道,需要我们大家行动起来,来银海工作当做像在自己家一样,用每度电、每张纸、每个零件、使用工具等要学会心疼、学会爱惜。比如以一台5P空调功率4000瓦时大概计算,每小时消耗4度电,一天消耗96度,一年就消耗35040度电,如果多台使用那数字更庞大了,假如我们一年不使用,或少使用,那节省的钱将是不少数目。所以我们每个员工在日常工作中从细节上,从身边小事做起,我们应当在自身上挖掘潜力,在工作岗位上找到自己的用武之地,发挥出自 己最大能量,为企业长远发展目标而不断努力和奋斗。 所以做为生产一线员工的我们,要时刻牢记;尊重、诚信、创新、 61 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 团队;的理念。我们保持有一颗‘滴水之恩,泉涌相报’感恩的心,珍惜现在工作岗位,带着主人翁责任感去工作,加陪努力,认真学习,提高技能,加强自身文化素质和提高生活素养。尊重领导,服从管理,把我们心拧成一团,把我们的手紧紧握在一起,团结一致,劲往一处使,努力构建***、健康的银海,使银海铝业发展越来越壮 大,越走越远,成为铝业强林中楷模, 由于知识浅薄,总结上不足之处或不对地方敬请公司领导给予指点和原谅,在此真心的祝福银海铝业员工们,生活如啃甘蔗一样一节比 一节甜;事业如登山一样一步比一步高, 第三届蒲公英助学社外联部工作总结 [第三届蒲公英助学社外联部工作总结]时光匆匆,从相聚到分离,总是时间很短很短,分开时候,我们有很多没做,很多的错误,很多工作做的不到位,为此我们留下了分别时很多遗憾,第三届蒲公英助学社外联部工作总结。第三届,在时光流逝的岁月里,也结束了。 作为第三届蒲公英助学社外联部的部长,我只能说,我已经带领我的团队为助学社的资金筹集出尽了力,虽然大家时常看到外联的娃们在办公室晃来晃去,在那里没事做的坐在那打酱油。可是,外联的工作性质决定了外联的工作情况,我们在有空的时候,我们可以整天在教学点打酱油:没空的的时候,会几天没见外联的娃。 62 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 作为一个刚上大一的大学生,我对外联的工作几乎是七窍通了六窍,虽说我特意在学校中汲取了一些经验,但是在实际中这些经验是帮不上忙得。所以,理事会在选外联部的部长的时候一定要选出有经验的人才。正是我没经验,所以外联的工作我做的很不好,让助学社的资金链陷入困境,是我这个外联部部长的工作不给力造成的。所以,我总结出一些经验来给下一届的部长做参考: 一、 经验和人脉是部长所要具备的两大要素 在助学社的前期工作中,外联部的工作的确不是很多,不像教学部那样工作一大堆。但是一回到拉赞助的战场上,外联部的部长经验就显得尤其重要,因为作为一个部长你要教会你的干事们怎么样在你没空或者你不在外联部时他们怎么样自己出去拉赞助。如果部长自己个人有过这方面的经验,可以很快通过带领整个部门的干事通过一两次赞助的现场实践就能让干事们了解拉赞助的要领等。这样就省了在回到英利后外联少了部长就做不了事的局面。还有一个很重要的是部长的人脉,这个部长可以不是很会管理外联,但是一定要有人脉基础。因为在英利这个小镇中,你没有人脉的话是很难从赞助商那里拿到一分钱的,那种找上门来的赞助在英利是很少的。所以,外联的部长要有很好的人脉基础,可以在助学社的资金链出现危机的时候用自己人脉关系网为助学社拉到赞助,当然一个人的力量毕竟是很有限 63 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 的,从而决定了部长要懂得充分的利用部门的人脉资源和助学社的人脉资源,这样才能在资金链出现危机的时候起到关键性的作用。 二、 外联的内部管理一定要严 外联的工作性质和助学社其他部门的工作性质很不一样,外联人很不受助学社规章制度的约束,而这正好考验了作为部门负责人对自己部门的管理能力。外联的干事们和部长几乎是整天在外面跑商店、公司、厂家等拉赞助。如果外联的工作成绩好的话,大家是有目共睹的,但是像第三届一样出去跑了几天,在最后才拉到那么点赞助费的时候,部门的内部管理和制度的建设就非常重要。所以,外联的内部管理和相关制度的制定或者部长对自己部门的管理以及约束是很重要的,“严”至少在我们没成绩出来之前,我们努力工作了,我们也就问心无愧了。 三、接班人的选择要慎重,选好了之后要做好接班人的交接工作和培养。 其实大家加入助学社都是怀着一颗感恩的心,一颗奉献之心从而走进助学社这个大家庭的,工作总结《第三届蒲公英助学社外联部工作总结》。助学社好,是我们每一个人的心愿,也是我们为之奋斗的目标。但是,接班人的选择和培养,这两方面的工作要做好。一个 64 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 好的负责人,不在乎他的能力有多强悍,最重要的是这个负责人知道怎么在危机的时刻怎么带领好整个部门走出困境,以及知道怎么实现资源的最大化利用。我相信,在这方面理事会会有比我更好的见解。但是,在接班人选出来之后,做好接班人的工作就要前一任部长的鼎力支持了。外联的性质,决定了外联的工作。在一个非常对外的部门里,如何做好自己分内的事,以及处理好上一届留下的一些问题或者利用好上一届留下来的资源等等,这些都要上一届部长很给力的帮助。这样,外联才能拓展出新的渠道,为助学社的资金链保驾护航。 三、 资金的筹集一定要有挑战精神和创造性思维 助学社经过三届的举办,已经很难在英利发展出新的赞助对象。而原有的赞助商因为我们的知名度和影响力不够,能够给出的赞助费也是在逐渐的减少。因为暂时还不知道第三届的社会反响怎么样,所以也不好随便的下结论。但是,把拉赞助的目标向英利之外扩大,是目前外联所必须处理的问题。虽然这一届我们出去拉赞助也为助学社第四届的活动埋下了一些好的赞助因数,但是把希望全部寄托到英利镇的企业家的身上是不明智的事情。所以,外联的赞助渠道一定要有创造性,如第二届外联就通过找广州的爱心组织拉到一笔大额的赞助等。所以,外联的赞助方式一定要在原有的基础上,再进行创新性增加,这样既可以创新赞助策划书又可以拉到更多的赞助。而我们也可以将拉赞助的目标向周围的村庄中,去其他市镇拉赞助等。这 65 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 样我们的资金链就会多样化,助学社的资金链就减少了很多的压力。所以,在前期工作中,作为一个部门的部长有什么想法等可以在准备好资料之后就可以去尝试,这样的创造性尝试,有时候往往会有意想不到的效果。 四、一定要协调好各部门的工作,处理好部门与部门之间的关系 外联虽说最主要的工作是为助学社筹集资金,为助学社活 动期间提供物资保障,但是,外联并不是独立于其他部门之外的一个部门,它与其他部门之间的关系非常之重要。尤其是在助学社活动期间的后期,要与宣传、文娱两个部门的干事,部长们处理好部门之间的关系,这样外联的工作才会做的更好。不要有着外联只要做好自己的本职工作就好了,而我们的后期工作更加的重要,因为只有我们和文娱、秘书、宣传等部门配合好了,我们的后期工作才能顺利的开展,才能为下一届的外联埋下好的种子,不能给下一届留下一个烂摊子,这是一个很不负责任的行为。 很多人会想,我加入外联是不是对义教没有起到一个很好的作用,会不会因为没教到小孩子们而留下遗憾等等。其实,你们也一样在教着小孩子,只不过你们是以着另一种方式教导了他们。当你真正的踏入这个部门的时候,你会觉得自己加入外联,不是个错误的选择。 66 ---------------------------------------------------------------范文最新推荐------------------------------------------------------ 我想第三届所有的外联干事都会这么想。因为第三届的外联团队很少人,所以我希望下一届加入外联的娃能更多,好让助学社能有更多的资金运转,让第三届的情况成为历史,不会再重演。 时光总是那么的匆匆,天下没有不散的宴席,从我们相聚到相离,短短的几天里,我们经历了欢声笑语、无奈、喜悦〃〃〃〃〃我们曾经为没有拉到赞助而失去信心,我们曾为寻找赞助目标而苦苦奔波,曾经为赞助商的表现而在路上大声开骂〃〃〃〃这些点滴都会留在第三届外联人的心中。希望助学社能在一届又一届的传承中越来越好。 邓海登 2012、2、13 67
/
本文档为【2016新编WAV文件格式分析详解】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索