表1 WAV文件的文件头
偏移地址
字节数
类型
内容
00H~03H
4
字符
资源交换文件标志(RIFF)注意字符大小写!
04H~07H
4
长整数
从下个地址开始到文件尾的总字节数
08H~0BH
4
字符
WAV文件标志(WAVE)注意字符大小写!
0CH~0FH
4
字符
波形格式标志(fmt)注意字符大小写!
10H~13H
4
整数
过滤字节(一般为00000010H)
14H~15H
2
整数
格式种类(值为1时,表示数据为线性PCM编码)
16H~17H
2
整数
通道数,单声道为1,双声音为2
18H~1BH
4
长整数
采样频率
1CH~1FH
4
长整数
波形数据传输速率(每秒平均字节数)
20H~21H
2
整数
数据的调整数(按字节计算)
22H~23H
2
整数
样本数据位数
表2 WAV声音文件的数据块
偏移地址
字节数
类型
内容
24H~27H
4
字符
数据标志符(data)注意字符大小写!
28H~2BH
4
长整型
采样数据总数
2CH...
...
...
采样数据
首先需要了解wav的这3个重要指标:采样率、采样位数、声道数。下面以16KHz, 16Bit, 单声道为例来说明。
采样率:(也称为采样速度或者采样频率)定义了每秒从连续信号中提取并组成离散信号的采样个数,单位用赫兹(Hz)来表示。采样频率的倒数是采样周 期(也称为采样时间),它表示采样之间的时间间隔。采样率为16KHz,表明每秒钟采样有16K次,即0.001秒内采集16个值。
采样位数:即采样值或取样值,用来衡量声音波动变化的参数,是指声卡在采集和播放声音文件时所使用数字声音信号的二进制位数。声卡的位客观地反映了数字声音信号对输入声音信号描述的准确程度。16Bit表示用计算机的16位(即2字节)来标示一个值。
声道数:是指支持能不同发声的音响的个数。常见的有单声道和双声道。
比特率:每秒传送的比特(bit)数,等于采样率*采样位数,单位为bps(Bit Per Second)。示例音频的比特率为256kbps。
了解了这些东西,我们就可以开始写代码了:
function wav_graph($file,$f=0,$w=0)
{
if(!is_file($file))return 0;
$fp=fopen($file,r);
$raw=fread($fp,36);//对应36个字节的文件头,包含该文件的一些信息
$str="";
$header=unpack('A4Riff/VSize/A4Wav/A4Head/VHeadSize/vPCM/vChannels/VSampleRate/VByteRate/vBlockAlign/vSampleBits', $raw);
//print_r($header);//查看文件头
foreach($header as $k=>$v)
$str.=$k.":".$v." ";
fseek($fp,36+$header['HeadSize']-16);
$raw=fread($fp,8);
$data=unpack('A4Data/VDataSize',$raw);
foreach($data as $k=>$v)
$str.=$k.":".$v." ";
$b=$header['SampleBits'];//样本数据位数
$c=$header['Channels'];//声道数
$l=$b*$c/8;//需要用16比特的原因就在这里,16比特代表采集位数是2个字节,除于8
$s=$data['DataSize']/$l;//文件数据长度/(样本采集位数*采集频率)=歌曲时间吧
$r=$header['SampleRate'];//采集频率
if($f) $h=pow(2,$b)/$f;//设定波的高度
else {$h=200;$f=pow(2,$b-1)/$h;}
if($w==0)$w=round($r/5);//后面的5是时间,1000表示按秒为单位
header("Content-type:image/png");//查看弹出数据时需要把画图的部分隐藏掉哦
$im=@imagecreate($s/$w,$h*$c*2);
$background_color = imagecolorallocate($im, 255, 255, 255);
$text_color = imagecolorallocate($im, 233, 14, 91);
$x=0;$y=array();$yn=array();
for($i=0;$i
$n=$l*$w;
while(1)
{
if($s==0) break;
if($s
$samples=fread($fp,5*$n);//后面的5是时间,1000表示按秒为单位
if($samples==FALSE)break;
$packed=unpack('s*',$samples);
foreach($packed as $k=>$v)
{
$cnt=($k-1)%($w*$l);
if($cnt>$c-1)continue;
$yn[$cnt]=$h*$cnt+$h-$v/$f;
imageline($im,$x,$y[$cnt],$x+1,$yn[$cnt],$text_color);
$y[$cnt]=$yn[$cnt];
$x++;
}
$s-=$n;
}
/**/
imagepng($im);
imagedestroy($im);
}
wav_graph('aa.wav');
?>
上传一张结果图