转载:http://www.voidcn.com/relative/p-fwdkigvh-bro.html
pcm 文件存储的是 原始的声音波型二进制流,没有文件头。
(1)首先要确认 pcm文件的每个采样数据 采样位数,一般为8bit或16bit。
(2)然后确定是双声道还是单声道,双声道是两个声道的数据交互排列,需要单独提取出每个声道的数据。
(3)然后确定有没有符号位,如采样点位16bit有符号位的的范围为-32768~32767
(4)确定当前操作系统的内存方式是大端,还是小端存储。具体看http://blog.csdn.net/u013378306/article/details/78904238
(5)根据以上四条对pcm文件进行解析,转化为10进制文件
注意:对于1-3可以在windows使用cooledit 工具设置参数播放pcm文件来确定具体参数,也可以使用以下java代码进行测试:
本例子的语音为: 静默1秒,然后说 “你好”,然后静默两秒。pcm文件下载路径:http://download.csdn.net/download/u013378306/10175068
package test; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; public class test { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { // TODO Auto-generated method stub File file = new File("3.pcm"); System.out.println(file.length()); int offset = 0; int bufferSize = Integer.valueOf(String.valueOf(file.length())) ; byte[] audioData = new byte[bufferSize]; InputStream in = new FileInputStream(file); in.read(audioData); float sampleRate = 20000; int sampleSizeInBits = 16; int channels = 1; boolean signed = true; boolean bigEndian = false; // sampleRate - 每秒的样本数 // sampleSizeInBits - 每个样本中的位数 // channels - 声道数(单声道 1 个,立体声 2 个) // signed - 指示数据是有符号的,还是无符号的 // bigEndian -是否为大端存储, 指示是否以 big-endian 字节顺序存储单个样本中的数据(false 意味着 // little-endian)。 AudioFormat af = new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian); SourceDataLine.Info info = new DataLine.Info(SourceDataLine.class, af, bufferSize); SourceDataLine sdl = (SourceDataLine) AudioSystem.getLine(info); sdl.open(af); sdl.start(); for(int i=0;i<audioData.length;i++) audioData[i]*=1; while (offset < audioData.length) { offset += sdl.write(audioData, offset, bufferSize); } } }
如果测试通过确定了参数就可以对pcm文件进行解析,如下java代码对每个采样数据为16bits,单声道的pcm,在操作系统内存为小端存储下解析为10进制文件。
package test; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStream; import java.math.BigInteger; public class ffff { /** * 采样位为16bits,小端存储,单声道解析为10进制文件 * @param args */ public static void main(String[] args) { try { File file = new File("3.pcm"); System.out.println(file.length()); System.out.println(file.length()); int bufferSize = Integer.valueOf(String.valueOf(file.length())); byte[] buffers = new byte[bufferSize]; InputStream in = new FileInputStream(file); in.read(buffers); String rs = ""; for (int i = 0; i < buffers.length; i++) { byte[] bs = new byte[2]; bs[0]=buffers[i+1];//小端存储, bs[1]=buffers[i]; int s = Integer.valueOf(binary(bs, 10)); i = i + 1; rs += " " + s; } writeFile(rs); in.close(); } catch (Exception e) { e.printStackTrace(); } } public static void writeFile(String s) { try { FileWriter fw = new FileWriter("hello3.txt"); fw.write(s, 0, s.length()); fw.flush(); fw.close(); } catch (Exception e) { e.printStackTrace(); } } public static String binary(byte[] bytes, int radix) { return new BigInteger(bytes).toString(radix);// 这里的1代表正数 } }
执行完可以查看hello.txt ,可以看到一开始振幅很小,如下,基本不超过100:
-15 -12 -18 -24 -17 -8 -8 -17 -22 -14 -5 -18 -47 -67 -60 -41 -28 -28 -23 -12 -6 -9 -13 -8 0 6 21 49 68 48 -2 -43 -47 -32 -22 -10 22 56
但说你好的时候,振幅变得很大:
-2507 -2585 -2600 -2596 -2620 -2670 -2703 -2674 -2581 -2468 -2378 -2305 -2200 -2018 -1774 -1523 -1307 -1127 -962 -806 -652 -505 -384 -313 -281 -241 -163
然后静默两秒,振幅又变的很小:
5 3 0 -4 -5 -6 -6 -7 -7 -8 -9 -8 -10 -10 -11 -10 -11 -11 -11 -11 -11 -11 -10 -9 -7 -6 -3 -2 -2 -3 -3 -3 -1 2 4 4
具体波形图可以使用python代码显示:
import numpy as np import pylab as pl import math import codecs file=codecs.open("hello3.txt","r") //原文代码file=codecs.open("hello3.txt","rb"),b是binary,以二进制方式读取,是错误的。 lines=" " for line in file.readlines(): lines=lines+line ys=lines.split(" ") yss=[] ays=list() axs=list() i=0 max1=pow(2,16)-1 for y in ys: if y.strip()=="": continue yss.append(y) for index in range(len(yss)): y1=yss[index] i+=1; y=int(y1) ays.append(y) axs.append(i) #print i file.close() pl.plot(axs, ays,"ro")# use pylab to plot x and y pl.show()# show the plot on the screen
得到波形图
这里音频振幅与audacity中呈现的结果吻合,只是这里把振幅放大以便用肉眼去观察。