使用 JAVA 从 wav 文件中提取振幅数组
我正在尝试从音频文件(WAV文件)中提取振幅数组。我将使用此振幅数组为给定的wav文件绘制振幅与时间关系图。我能够自己绘制图形,但不知道如何从java中的给定音频(wav)文件中提取振幅?
我正在尝试从音频文件(WAV文件)中提取振幅数组。我将使用此振幅数组为给定的wav文件绘制振幅与时间关系图。我能够自己绘制图形,但不知道如何从java中的给定音频(wav)文件中提取振幅?
下面是一个可以使用的帮助程序类。该方法是获取振幅所需的方法:getSampleInt()
File file = ...;
WavFile wav = new WavFile(file);
int amplitudeExample = wav.getSampleInt(140); // 140th amplitude value.
for (int i = 0; i < wav.getFramesCount(); i++) {
int amplitude = wav.getSampleInt(i);
// Plot.
}
它还可以播放文件,以便您可以测试它,但只能播放8位或16位文件。对于其他情况,您只能阅读它们。
另外,请查看这些图表以了解WAV文件由哪些部分组成,并更好地了解此类的功能。
public class WaveFile {
public final int NOT_SPECIFIED = AudioSystem.NOT_SPECIFIED; // -1
public final int INT_SIZE = 4;
private int sampleSize = NOT_SPECIFIED;
private long framesCount = NOT_SPECIFIED;
private int sampleRate = NOT_SPECIFIED;
private int channelsNum;
private byte[] data; // wav bytes
private AudioInputStream ais;
private AudioFormat af;
private Clip clip;
private boolean canPlay;
public WaveFile(File file) throws UnsupportedAudioFileException, IOException {
if (!file.exists()) {
throw new FileNotFoundException(file.getAbsolutePath());
}
ais = AudioSystem.getAudioInputStream(file);
af = ais.getFormat();
framesCount = ais.getFrameLength();
sampleRate = (int) af.getSampleRate();
sampleSize = af.getSampleSizeInBits() / 8;
channelsNum = af.getChannels();
long dataLength = framesCount * af.getSampleSizeInBits() * af.getChannels() / 8;
data = new byte[(int) dataLength];
ais.read(data);
AudioInputStream aisForPlay = AudioSystem.getAudioInputStream(file);
try {
clip = AudioSystem.getClip();
clip.open(aisForPlay);
clip.setFramePosition(0);
canPlay = true;
} catch (LineUnavailableException e) {
canPlay = false;
System.out.println("I can play only 8bit and 16bit music.");
}
}
public boolean isCanPlay() {
return canPlay;
}
public void play() {
clip.start();
}
public void stop() {
clip.stop();
}
public AudioFormat getAudioFormat() {
return af;
}
public int getSampleSize() {
return sampleSize;
}
public double getDurationTime() {
return getFramesCount() / getAudioFormat().getFrameRate();
}
public long getFramesCount() {
return framesCount;
}
/**
* Returns sample (amplitude value). Note that in case of stereo samples
* go one after another. I.e. 0 - first sample of left channel, 1 - first
* sample of the right channel, 2 - second sample of the left channel, 3 -
* second sample of the rigth channel, etc.
*/
public int getSampleInt(int sampleNumber) {
if (sampleNumber < 0 || sampleNumber >= data.length / sampleSize) {
throw new IllegalArgumentException(
"sample number can't be < 0 or >= data.length/"
+ sampleSize);
}
byte[] sampleBytes = new byte[4]; //4byte = int
for (int i = 0; i < sampleSize; i++) {
sampleBytes[i] = data[sampleNumber * sampleSize * channelsNum + i];
}
int sample = ByteBuffer.wrap(sampleBytes)
.order(ByteOrder.LITTLE_ENDIAN).getInt();
return sample;
}
public int getSampleRate() {
return sampleRate;
}
public Clip getClip() {
return clip;
}
}
我尝试了你的代码,经过一些小的更改,它创造了一个结果。代码输出的数据有什么问题?
我更改了以下行:
// create file input stream
DataInputStream fis = new DataInputStream(new FileInputStream(wavFile));
// create byte array from file
arrFile = new byte[(int) wavFile.length()];
fis.readFully(arrFile); // make sure you always read the full file, you did not check its return value, so you might be missing some data
我改变的第二件事是:
System.out.println(Arrays.toString(s.extractAmplitudeFromFile(f)));
在您的Main方法中,由于您只是打印出arary的地址。在这些更改之后,代码会发出一个具有值的数组,该值似乎与所需的数据相关联。
您错过了什么,或者您对数据的期望是什么?你能再澄清一下这个问题吗?