Java程序获取和修改.wav音频文件的内部结构

(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/79498075冷血之心的博客)

       wav音频文件是一种无损的音频文件,相对于MP3来说音质较好,当然文件大小也很大。

        A WAVE file is often just a RIFF file with a single “WAVE” chunk which consists of two sub-chunks – a “fmt ” chunk specifying the data format and a “data” chunk containing the actual sample data. Call this form the “Canonical form”

其文件的内部格式如下:


用表格统计各个部分的含义如下:



一个简单的示例如下所示:



获取内部结构

那么我们如何使用Java程序来获取wav文件的内部结构信息呢?使用RandomAccessFile实现,代码如下所示:

package cn.pak1;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class My {

	public static void main(String[] args) throws IOException {

		File f = new File("C://Users//yangwenqiang//Desktop//auoy.wav");
		RandomAccessFile rdf = null;
		rdf = new RandomAccessFile(f, "r");
		System.out.println("audio size: " + toInt(read(rdf, 4, 4))); // 音频文件大小

		System.out.println("audio format: " + toShort(read(rdf, 20, 2))); // 音频格式,1-PCM

		System.out.println("num channels: " + toShort(read(rdf, 22, 2))); // 1-单声道;2-双声道

		System.out.println("sample rate: " + toInt(read(rdf, 24, 4))); // 采样率、音频采样级别

		System.out.println("byte rate: " + toInt(read(rdf, 28, 4))); // 每秒波形的数据量

		System.out.println("block align: " + toShort(read(rdf, 32, 2))); // 采样帧的大小

		System.out.println("bits per sample: " + toShort(read(rdf, 34, 2))); // 采样位数

		rdf.close();
	}

	public static int toInt(byte[] b) {
		return ((b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0] << 0));
	}

	public static short toShort(byte[] b) {
		return (short) ((b[1] << 8) + (b[0] << 0));
	}

	public static byte[] read(RandomAccessFile rdf, int pos, int length) throws IOException {
		rdf.seek(pos);
		byte result[] = new byte[length];
		for (int i = 0; i < length; i++) {
			result[i] = rdf.readByte();
		}
		return result;
	}
}

结果如下所示:


我们分别得出该音频文件的大小、format、通道数量、采样率、字节率等消息。

       RandomAccessFile的构造函数除了指定了要写入了文件,还有另外一个参数:mod,主要用来指定打开文件的访问模式。

      

使用了 RandomAccessFile,我们通过seek方法设置到此文件开头测量到的文件指针偏移量,在该位置发生下一个读取操作,得到了音频文件的内部结构。


修改内部结构

修改内部结构,我们需要将RandomAccessFile的构造函数模式设为“rw”,并且write方法实现修改音频文件内部结构,代码如下所示:

package cn.pak1;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

public class My {

	public static void main(String[] args) throws IOException {

		File f = new File("C://Users//yangwenqiang//Desktop//auoy.wav");
		RandomAccessFile rdf = null;
		rdf = new RandomAccessFile(f, "rw");
		write(rdf, 22);
		
		System.out.println("audio size: " + toInt(read(rdf, 4, 4))); // 音频文件大小

		System.out.println("audio format: " + toShort(read(rdf, 20, 2))); // 音频格式,1-PCM

		System.out.println("num channels: " + toShort(read(rdf, 22, 2))); // 1-单声道;2-双声道

		System.out.println("sample rate: " + toInt(read(rdf, 24, 4))); // 采样率、音频采样级别

		System.out.println("byte rate: " + toInt(read(rdf, 28, 4))); // 每秒波形的数据量

		System.out.println("block align: " + toShort(read(rdf, 32, 2))); // 采样帧的大小

		System.out.println("bits per sample: " + toShort(read(rdf, 34, 2))); // 采样位数

		rdf.close();
	}

	public static int toInt(byte[] b) {
		return ((b[3] << 24) + (b[2] << 16) + (b[1] << 8) + (b[0] << 0));
	}

	public static short toShort(byte[] b) {
		return (short) ((b[1] << 8) + (b[0] << 0));
	}

	public static byte[] read(RandomAccessFile rdf, int pos, int length) throws IOException {
		rdf.seek(pos);
		byte result[] = new byte[length];
		for (int i = 0; i < length; i++) {
			result[i] = rdf.readByte();
		}
		return result;
	}

	public static void write(RandomAccessFile rdf, int pos) throws IOException {
		rdf.seek(pos);
		byte[] b = {02,00};
		rdf.write(b);

	}
}

结果如下所示:


我们通过代码,就将通道数修改为2。实现其内部结构的修改。



以上就是如何使用Java代码获取和修改wav音频文件内部结构的小Demo。如果对你有帮助,记得点赞哦~欢迎大家关注我的博客,可以进群366533258(请备注来源)一起交流学习哦~


本群给大家提供一个学习交流的平台,内设菜鸟Java管理员一枚、精通算法的金牌讲师一枚、Android管理员一枚、蓝牙BlueTooth管理员一枚、Web前端管理一枚以及C#管理一枚。欢迎大家进来交流技术。



要用Java绘制一个.wav音频文件的时域图,可以按照以下步骤进行: 1. 读取.wav文件获取其中的音频数据。 2. 将音频数据转换为可绘制的格式,比如BufferedImage。 3. 绘制时域图,将转换后的音频数据按照时间序列进行绘制,形成一条连续的波形线。 下面是一个用Java绘制.wav音频文件时域图的示例代码: ```java import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import javax.imageio.ImageIO; import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.UnsupportedAudioFileException; public class WaveformGenerator { public static void main(String[] args) { // 指定.wav文件路径 String filePath = "test.wav"; // 读取.wav文件获取音频数据 try (AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(new File(filePath))) { int bytesPerFrame = audioInputStream.getFormat().getFrameSize(); int numBytes = (int) (audioInputStream.getFrameLength() * bytesPerFrame); byte[] audioBytes = new byte[numBytes]; int numBytesRead = 0; while (numBytesRead < audioBytes.length) { int numBytesRemaining = audioBytes.length - numBytesRead; int numBytesToRead = audioInputStream.read(audioBytes, numBytesRead, numBytesRemaining); if (numBytesToRead == -1) { break; } numBytesRead += numBytesToRead; } // 将音频数据转换为可绘制的格式 int width = 1000; // 绘制区域宽度 int height = 500; // 绘制区域高度 BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); int numSamples = numBytes / bytesPerFrame; int samplesPerPixel = numSamples / width; int numPixels = numSamples / samplesPerPixel; int yCenter = height / 2; int oldX = 0, oldY = yCenter; g.setColor(Color.BLACK); // 绘制时域图 for (int i = 1; i < numPixels; i++) { int sum = 0; for (int j = 0; j < samplesPerPixel; j++) { int index = (i - 1) * samplesPerPixel + j; int sample = 0; if (bytesPerFrame == 1) { sample = audioBytes[index]; } else if (bytesPerFrame == 2) { sample = audioBytes[index * 2] + (audioBytes[index * 2 + 1] << 8); } sum += sample; } int x = i; int y = yCenter + (sum / samplesPerPixel) / 65536; g.drawLine(oldX, oldY, x, y); oldX = x; oldY = y; } // 将绘制结果保存为图片文件 File outputfile = new File("waveform.png"); ImageIO.write(image, "png", outputfile); } catch (UnsupportedAudioFileException | IOException e) { e.printStackTrace(); } } } ``` 需要注意的是,上述代码只适用于采样精度为8或16位、单声道的.wav文件。如果需要处理其他类型的音频文件,需要对代码进行相应的修改
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

温柔狠角色

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值