java wav音频文件播放器demo

259 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

测试文件

百度网盘 : pan.baidu.com/s/1U93rkCs-… 提取码:xhn8

源码

import java.io.FileInputStream;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;

/**
 * 简易wave音频文件播放器
* @author 作者 luhua
* @version 创建时间:2021年5月14日 下午3:20:11
*/
public class WavePlayer {
	
	
	public static void main(String[] args) throws Exception {
		String path = "F:\\testFile\\audio\\b.wav";
		if(null != args && args.length > 0) {
			path = args[0];
		}
		FileInputStream fis = new FileInputStream(path);
		/**解析wav头*/
		WavHeard pasrWaveHeard = pasrWaveHeard(fis);
		if(null != pasrWaveHeard) {
			System.out.println(pasrWaveHeard);
			AudioFormat.Encoding encoding =  new AudioFormat.Encoding("PCM_SIGNED");
			//编码格式,采样率,每个样本的位数,声道,帧长(字节),帧数,是否按big-endian字节顺序存储
			AudioFormat format = new AudioFormat(encoding,pasrWaveHeard.sampleRate, pasrWaveHeard.formatSize, 
					pasrWaveHeard.numChannels, pasrWaveHeard.blockAlign, pasrWaveHeard.sampleRate ,false);
			SourceDataLine auline = null;
			DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
			System.out.println(format);
			auline = (SourceDataLine) AudioSystem.getLine(info);
			auline.open(format);
			auline.start();
			byte[] b = new byte[pasrWaveHeard.bytesPerSecond];
			int len = 0;
			while((len = fis.read(b))>0) {
				auline.write(b, 0, len);
			}
			auline.close();
		}
	}
	
	
	public static WavHeard pasrWaveHeard(FileInputStream fis) throws Exception{
		WavHeard wavHeard = new WavHeard();
		byte[] b = new byte[4];
		/**RIFF部分*/
		fis.read(wavHeard.riffType);
		if(!"RIFF".equalsIgnoreCase(new String(wavHeard.riffType))) {
			System.out.println("This is not a valid wav(RIFF) file.");
			return null;
		}
		/**riffSize*/
		fis.read(b);
		wavHeard.riffSize = (b[3]&0xff)<<24|(b[2]&0xff)<<16|(b[1]&0xff)<<8|(b[0]&0xff);
		/**wave*/
		fis.read(wavHeard.waveType);

		/**FMT */
		fis.read(wavHeard.formatType);
		if(!"FMT ".equalsIgnoreCase(new String(wavHeard.formatType))) {
			System.out.println("This is not a valid wav(FMT) file.");
			return null;
		}

		/**表示该区块数据的长度(不包含FMT 和fSize的长度)*/
		fis.read(b);
		wavHeard.formatSize = (b[3]&0xff)<<24 | (b[2]&0xff)<<16 | (b[1]&0xff)<<8 | (b[0]&0xff);

		/**PCM音频数据的值为1*/
		b = new byte[2];
		fis.read(b);
		wavHeard.compressionCode = (short) ((b[1]&0xff)<<8 | (b[0]&0xff));
		
		/**音频数据的声道数,1:单声道,2:双声道*/
		fis.read(b);
		wavHeard.numChannels = (short) ((b[1]&0xff)<<8 | (b[0]&0xff));
		
		/**采样率*/
		b = new byte[4];
		fis.read(b);
		wavHeard.sampleRate = (b[3]&0xff) <<24 | (b[2]&0xff)<<16 | (b[1]&0xff)<<8 | (b[0]&0xff);

		/**每秒数据字节数*/
		fis.read(b);
		wavHeard.bytesPerSecond = (b[3]&0xff) <<24 | (b[2]&0xff)<<16 | (b[1]&0xff)<<8 | (b[0]&0xff);
		
		/**每个采样所需字节数*/
		b = new byte[2];
		fis.read(b);
		wavHeard.blockAlign = (short) ((b[1]&0xff)<<8 | (b[0]&0xff));
		
		/**每个采样存储的bit数*/
		fis.read(b);
		wavHeard.bitsPerSample = (short) ((b[1]&0xff)<<8 | (b[0]&0xff));
		
		/**data*/
		fis.read(wavHeard.dataType);
		
		/**dataSize*/
		b = new byte[4];
		fis.read(b);
		wavHeard.dataSize = (b[3]&0xff) <<24 | (b[2]&0xff)<<16 | (b[1]&0xff)<<8 | (b[0]&0xff);
		return wavHeard;
	}

}

class WavHeard{  
	public byte[] riffType = new byte[4];    	//4byte,资源交换文件标志:RIFF     
	public int    riffSize;       				//4byte,从下个地址到文件结尾的总字节数   
	public byte[]   waveType = new byte[4];  	//4byte,wav文件标志:WAVE      
	public byte[]   formatType = new byte[4]; 	//4byte,波形文件标志:FMT(最后一位空格符)   
	public int    formatSize;     				//4byte,音频属性(compressionCode,numChannels,sampleRate,bytesPerSecond,blockAlign,bitsPerSample)所占字节数  
	public short  compressionCode;				//2byte,格式种类(1-线性pcm-WAVE_FORMAT_PCM,WAVEFORMAT_ADPCM)  
	public short  numChannels;    				//2byte,通道数  
	public int    sampleRate;     				//4byte,采样率  
	public int    bytesPerSecond; 				//4byte,传输速率  
	public short  blockAlign;     				//2byte,数据块的对齐,即DATA数据块长度  
	public short  bitsPerSample;  				//2byte,采样精度-PCM位宽  
	public byte[]   dataType = new byte[4];     //4byte,数据标志:data  
	public int    dataSize;       				//4byte,从下个地址到文件结尾的总字节数,即除了wav header以外的pcm data length  
	
	
	@Override
	public String toString() {
		return "------------------RIFF------------------\n"+ 
			   "\n riffType\t:"+new String(riffType)+
			   "\n riffSize\t:"+riffSize+
			   "\n waveType\t:"+new String(waveType)+
			   "\n\n------------------FORMAT----------------\n"+
			   "\n formatType\t:"+ new String(formatType) +
			   "\n formatSize\t:"+ formatSize +
			   "\n compressionCode:"+ compressionCode +
			   "\n numChannels\t:" + numChannels +
			   "\n sampleRate\t:" + sampleRate +
			   "\n bytesPerSecond\t:" + bytesPerSecond +
			   "\n blockAlign\t:" + blockAlign +
			   "\n bitsPerSample\t:" + bitsPerSample +
			   "\n dataType\t:" + new String(dataType) +
			   "\n dataSize\t:" + dataSize + 
			   "\n\n-----------------------------------------";
	}
	
}

相关资料

wav音频文件解析 java播放pcm音频文件