Java获取Wav文件的采样率SampleRate

Java获取Wav文件的采样率SampleRate

  • 1.功能需求
  • 2.解决方案
    • 2.1 方案1
      • 2.1.1 代码实例
      • 2.1.2 效果演示
    • 2.2 方案2
      • 2.2.1 代码实例
      • 2.2.2 效果演示
  • 3.分析总结

系统:Win10
Java:1.8.0_333
IDEA:2020.3.4

1.功能需求

在一个项目过程中,我需要获取 wav 文件的采样率(SampleRate),后来我就上网搜了一下教程和代码样例结果发现网上的代码千篇一律,都是使用位偏移法获取值,该方法好像有个 bug,在采样率为 44100Hz 的时候,获取的值是负数,后来在不断的查找和学习下终于解决了这个问题

2.解决方案

这里用到几个测试音频文件,已经上传到资源文件里去了,设置了0积分下载,大家有兴趣可以下载下来测试玩玩
https://download.csdn.net/download/qq_35132089/86723016

2.1 方案1

2.1.1 代码实例

这里是读取 wav 文件的头文件对应位置的值然后进行数值转换

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.List;

public class WavParsing {
    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList();
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\a.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\b.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\c.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\d.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\e.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\f.wav");
        for (String path : list) {
            File file = new File(path);
            RandomAccessFile rdf = null;
            /**
             * "r": 以只读方式打开。调用结果对象的任何 write 方法都将导致抛出 IOException。
             * "rw": 打开以便读取和写入。
             * "rws": 打开以便读取和写入。相对于 "rw","rws" 还要求对“文件的内容”或“元数据”的每个更新都同步写入到基础存储设备。
             * "rwd" : 打开以便读取和写入,相对于 "rw","rwd" 还要求对“文件的内容”的每个更新都同步写入到基础存储设备。
             */
            rdf = new RandomAccessFile(file, "r");
            System.out.println(file.getName() + " SampleRate:" + toInt(read(rdf)));  // 采样率、音频采样级别 8000 = 8KHz
            rdf.close();
        }
    }

    public static int toInt(byte[] b) {
        return u(b[15]) * 16777216 + u(b[14]) * 65536 + u(b[13]) * 256 + u(b[12]);
    }

    private static int u(int n) {
        return n & 255;
    }

    public static byte[] read(RandomAccessFile rdf) throws IOException {
        byte[] bytes = new byte[12];
        rdf.read(bytes);
        bytes = new byte[24];
        rdf.read(bytes);
        rdf.close();
        return bytes;
    }
}

2.1.2 效果演示

这里运行测试了一下,发现获取的采样率都是正确的
Java获取Wav文件的采样率SampleRate_第1张图片

2.2 方案2

2.2.1 代码实例

还有一种比较简单的方法,就是用别人已经造好的轮子,这些对应方法已经有不少前辈写成了对应的实现功能,我们只需要引入对应 jar 包,就可以直接调用对应方法。使用这方法的优点在于,还可以调用其封装的方法获取其他类似时长、格式、声道等数据
首先需要引入对应jar包,我这里使用的maven项目,所以导入其对应依赖

<!-- 获取音频信息 -->
<dependency>
    <groupId>org</groupId>
    <artifactId>jaudiotagger</artifactId>
    <version>2.0.3</version>
</dependency>

测试代码

import org.jaudiotagger.audio.AudioFile;
import org.jaudiotagger.audio.wav.WavFileReader;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class AudioWavUtils {

    public static void main(String[] args) throws Exception {
        List<String> list = new ArrayList();
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\a.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\b.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\c.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\d.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\e.wav");
        list.add("C:\\Users\\Li\\Desktop\\WavResource\\f.wav");
        for (String path : list) {
            WavFileReader fileReader = new WavFileReader();
            AudioFile audioFile = fileReader.read(new File(path));
            System.out.println(audioFile.getFile().getName() + " SampleRate:" + audioFile.getAudioHeader().getSampleRate());
        }
    }
}

2.2.2 效果演示

这里运行一下发现也是能正常获取采样率的
Java获取Wav文件的采样率SampleRate_第2张图片

3.分析总结

这次问题花了我大概半天的时间解决,究其原因在于我一开始拿网上分享的代码测试,得到的结果是个负数,我就认为是代码有问题或者是音频有问题;然后我先从代码层面考虑,这里走了不少弯路,因为我对于音频文件的结构不太了解。
后来,我不断查找资料,发现大家写的代码都是这样

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;
}

后来经过一段无效的测试后,我尝试换几个采样率小点的试试,因为我看到这里使用了移位运算符,想到负数可能是由于取值范围导致的。所以当我把采样率改小测试成功后,我就明白可能这就是这段代码的漏洞了。那么为什么大家都是这么写的呢??
我看了下那篇文章的日期,2011年,想来是时代的进步,音频的发展,导致现在使用的音频的采样率都上去了,而有很大一部分写文章就直接抄过来,甚至都不测试一下,简直误人子弟。
不过第一批写那个文章的前辈肯定是正确的,时代在进步,技术也随着更新迭代,一段代码不能永远保持他的有效性,我们需要从中学到的是其中解决问题的思路

你可能感兴趣的:(Java,案例,Java,Wav,SampleRate)