相关知识,仅供参考:
一、WAV文件介绍
WAV是一种无损音频文件格式,它包含了音频数据和元数据。在WAV文件中,音频数据以采样率、位深和声道数等信息存储。我们需要读取这些信息并对音频数据进行相应处理。
1.1 WAV 文件结构
RIFF Header:
----------------------------------
Chunk ID(4字节):通常为“RIFF”,标识这是一个RIFF文件。
Chunk Size(4字节):RIFF chunk的大小,不包括Chunk ID和Chunk Size本身。
Format(4字节):通常为“WAVE”,标识这是WAVE文件。
Format Chunk(fmt chunk):
---------------------------------
Subchunk1 ID(4字节):通常为“fmt ”,标识格式子块。
Subchunk1 Size(4字节):此子块的大小。对于PCM格式,通常为16。
Audio Format(2字节):音频格式标识符。对于PCM格式,值为1。
Number of Channels(2字节):声道数,通常为1(单声道)或2(立体声)。
Sample Rate(4字节):采样率,比如44100 Hz。
Byte Rate(4字节):每秒的字节数,计算公式为 Sample Rate * Number of Channels * Bits per Sample / 8。
Block Align(2字节):每个采样帧的字节数,计算公式为 Number of Channels * Bits per Sample / 8。
Bits per Sample(2字节):每个样本的位深度,比如16位。
Data Chunk:
------------------------------
Subchunk2 ID(4字节):通常为“data”,标识数据子块。
Subchunk2 Size(4字节):音频数据的大小。
Data:实际的音频数据。
1.2采样率介绍
采样频率(Sampling Frequency),也称为采样速度或采样率,是指每秒钟从连续信号中提取并组成离散信号的采样数量,用赫兹(Hz)来表示。简单来说,采样频率描述了计算机每秒钟采集多少个声音样本。这一参数对声音文件的音质和音调有直接影响,并且是衡量声卡和声音文件质量的重要标准。
采样频率的倒数叫做采样周期或采样时间,表示的是两个连续采样之间的时间间隔。例如,如果采样频率为 44.1 kHz(即每秒钟采集 44,100 个样本),那么采样周期就是约 22.7 微秒。较高的采样频率通常意味着更高的音频质量,因为它可以捕捉到更细致的声音细节。
1.3采样率与播放速度
采样率(采样频率)会影响音频的播放速度和音质,当采样率发生变化时,音频的播放速度和音高都会受到影响,具体来说:
-
播放速度:采样率越高,每秒钟采集的样本越多,相同长度的音频文件在高采样率下会播放得更快。例如,如果你以 44.1 kHz 的采样率播放一个原本是 8 kHz 采样率的音频文件,音频将会比正常速度播放得更快,因为高采样率会导致每秒播放的样本数增多,从而加快播放速度。所以在TTS时候,看服务传输的音频流是多少赫兹的然后再去添加头部元数据信息。
-
音高:采样率的变化也会影响音高,如果你将一个低采样率的音频提升到高采样率播放,会使得音频的音高变高,这类似于音频被“加速”了。
1.4采样率转换
由于音频文件的采样率不一定统一,当播放或处理不同采样率的音频时,需要进行采样率转换(Sample Rate Conversion),这种转换的过程包括以下几个步骤:
-
重采样:将音频数据从原始采样率转换到目标采样率。重采样的过程涉及到插值和降采样,以确保音频的质量在转换过程中尽可能保持一致。
-
时间伸缩:在转换过程中,可能需要对音频进行时间伸缩,以调整播放速度和音高。
-
滤波器:在重采样时,通常会使用滤波器来防止混叠效应(Aliasing)并平滑音频信号。
采样率转换可以在音频处理软件或音频播放器中自动完成,但在某些专业的音频处理应用中,用户可能需要手动设置和调整采样率,以获得最佳的音质和播放效果。
二、JSSRC 处理库
实际业务中并不是所有音频的采样率都是统一的,特别是做智能语音,再做ASR过程中,如果音频采样率配置错误,会导致音频识别错误,造成严重的业务灾难。这时候我们需要改变wav音频文件的采样率,以满足特定的需求。现在给大家介绍一个开源的java 音频处理库JSSRC。
2.1. 项目介绍
JSSRC(Java-based Sample Rate Converter),正如其名,是一个旨在提供高质量音频重采样的Java实现。这个项目源于Naoki Shibata的SSRC——一个被广泛认可的C语言版本高精度音频采样率转换器。经过Naohide Sano的努力,将这一杰出的工作转化为Java语言,最终,通过一系列细微但至关重要的调整,形成了今天这样一个易于集成与使用的Java服务,让音频重采样变得前所未有的简单和高效。
github地址:https://github.com/hutm/JSSRC
2.2. 项目技术分析
JSSRC的核心在于它的高效算法移植与优化。原生基于C的SSRC因其在保持音质的同时能有效转换采样率而著称,JSSRC继承了这一优良传统,并且特别适应于Java生态系统。通过利用Java的多线程能力和内存管理特性,JSSRC不仅保证了音频转换的高保真度,还确保了在复杂应用环境中的稳定性和效率。这使得它成为跨平台应用的理想选择,无论是桌面端、Web服务还是移动开发领域。
2.3实例代码
/**
*
* 改变wav采样率
*--------------------
* @author 赵海洋
* @date 2024-9-16
* @des 主要应用与ASR语音识别过程中,部分wav文件采样率与模型的不匹配,导致语音识别错误调整采样
*率涉及到重新采样.
*
**/
private void simpleDownSample() {
File BeforeSampleChangedFile = new File(BeforeSampleChangedFilePath);
File SampleChangedFile = new File(SampleChangedFilePath);
try {
FileInputStream fileInputStream = new FileInputStream(BeforeSampleChangedFile);
FileOutputStream fileOutputStream = new FileOutputStream(SampleChangedFile);
new SSRC(fileInputStream, fileOutputStream, 8000, 44100,
2,
2,
1, Integer.MAX_VALUE, 0, 0, true);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
其中8000就是待转换的采样率,44100就是目标采样率,可以从低转到高,也可以高转低。
2.4 纯java实现
import com.sun.media.sound.WaveFileReader;
import com.sun.media.sound.WaveFileWriter;
import javax.sound.sampled.*;
import java.io.*;
/**
*
* 改变wav采样率
*--------------------
* @author 赵海洋
* @date 2024-9-16
* @des 主要应用与ASR语音识别过程中,部分wav文件采样率与模型的不匹配,导致语音识别错误调整采样
*率涉及到重新采样,即将音频数据按新的采样率进行插值或降采样。这可能涉及复杂的信号处理算法,
* 通常可以使用现成的库来完成。例如,TarsosDSP库是一个常用的音频处理库,可以用于实现这种功能。
*
* */
public class WavReSample {
/**
*
* @param newSampleRate 新的采样率
* @param inputFilePath 需要转化的文件
* @param outputFilePath 输出的文件路径
*
* */
public static void reSampleRate(int newSampleRate,String inputFilePath,String outputFilePath) throws IOException, UnsupportedAudioFileException {
try (AudioInputStream inputAIS = AudioSystem.getAudioInputStream(new File(inputFilePath))) {
AudioFormat inputFormat = inputAIS.getFormat();
AudioFormat outputFormat = new AudioFormat(
AudioFormat.Encoding.PCM_SIGNED,
newSampleRate, // New sample rate
inputFormat.getSampleSizeInBits(),
inputFormat.getChannels(),
inputFormat.getFrameSize(),
newSampleRate, // New sample rate
inputFormat.isBigEndian()
);
try (AudioInputStream outputAIS = AudioSystem.getAudioInputStream(outputFormat, inputAIS)) {
AudioSystem.write(outputAIS, AudioFileFormat.Type.WAVE, new File(outputFilePath));
}
}
}
public static void main(String[] args) throws Exception {
reSampleRate(44100,"E://out.wav","E://output2.wav");
}
}