【发布时间】:2018-08-16 16:16:48
【问题描述】:
在网上搜索了数周后,我找到了以下代码 在 Java 中计算给定
.wav文件的幅度。现在 问题是它根本不能很好地扩展大音频文件,比如 假设 30 分钟,produces 数组很大。
为了绘制它,我使用的是 JavaFX created this repository(由于我现在有几天没有提交代码,所以那里的代码可能会有所不同)。
所以:
/**
* Get Wav Amplitudes
*
* @param file
* @return
* @throws UnsupportedAudioFileException
* @throws IOException
*/
private int[] getWavAmplitudes(File file) throws UnsupportedAudioFileException , IOException {
System.out.println("Calculting WAV amplitudes");
int[] amplitudes = null;
//Get Audio input stream
try (AudioInputStream input = AudioSystem.getAudioInputStream(file)) {
AudioFormat baseFormat = input.getFormat();
Encoding encoding = AudioFormat.Encoding.PCM_UNSIGNED;
float sampleRate = baseFormat.getSampleRate();
int numChannels = baseFormat.getChannels();
AudioFormat decodedFormat = new AudioFormat(encoding, sampleRate, 16, numChannels, numChannels * 2, sampleRate, false);
int available = input.available();
amplitudes = new int[available];
//Get the PCM Decoded Audio Input Stream
try (AudioInputStream pcmDecodedInput = AudioSystem.getAudioInputStream(decodedFormat, input)) {
final int BUFFER_SIZE = 4096; //this is actually bytes
System.out.println(available);
//Create a buffer
byte[] buffer = new byte[BUFFER_SIZE];
//Read all the available data on chunks
int counter = 0;
while (pcmDecodedInput.readNBytes(buffer, 0, BUFFER_SIZE) > 0)
for (int i = 0; i < buffer.length - 1; i += 2, counter += 2) {
if (counter == available)
break;
amplitudes[counter] = ( ( buffer[i + 1] << 8 ) | buffer[i] & 0xff ) << 16;
amplitudes[counter] /= 32767;
amplitudes[counter] *= WAVEFORM_HEIGHT_COEFFICIENT;
}
} catch (Exception ex) {
ex.printStackTrace();
}
} catch (Exception ex) {
ex.printStackTrace();
}
//System.out.println("Finished Calculting amplitudes");
return amplitudes;
}
然后我像这样处理振幅:
/**
* Process the amplitudes
*
* @param sourcePcmData
* @return An array with amplitudes
*/
private float[] processAmplitudes(int[] sourcePcmData) {
System.out.println("Processing WAV amplitudes");
//The width of the resulting waveform panel
int width = waveVisualization.width;
System.out.println("P Width :" + width);
float[] waveData = new float[width];
int samplesPerPixel = sourcePcmData.length / width;
//Calculate
float nValue;
for (int w = 0; w < width; w++) {
//if (isCancelled())
// break;
//For performance keep it here
int c = w * samplesPerPixel;
nValue = 0.0f;
//Keep going
for (int s = 0; s < samplesPerPixel; s++) {
//if (isCancelled())
// break;
nValue += ( Math.abs(sourcePcmData[c + s]) / 65536.0f );
}
//Set WaveData
waveData[w] = nValue / samplesPerPixel;
}
System.out.println("Finished Processing amplitudes");
return waveData;
}
输出是这样的:
【问题讨论】:
-
对它们进行采样。取每个 X 的平均值。或最大值。或敏。或者介于两者之间。用户不需要也无法处理每个样本的幅度 - 所以对样本进行采样。
-
@BoristheSpider 请提供代码示例。我对此很陌生。添加答案:)
-
您的代码已经通过计算有多少像素并进行平均来进行聚合 - 只需将该代码移入并使您的数组大小与现在的
waveData相同。我认为你理解你的代码并自己修改它会比我为你做的提供更多的信息。 -
@BoristheSpider 嗨,我已经添加了一个答案,我尽力做到最好,内存中没有保存巨大的数组,最终的振幅数组非常小。只有一件事(我不知道振幅数组的最佳最终尺寸应该是什么,所以我将其保留为 100.000)我是否也应该按照您所说的那样实现最小值和最大值?在这里需要一个意见我迷路了:)
-
看起来是正确的方法。对于子数组的大小 - 为什么不将您需要多少样本以及从中计算数组长度的方法传递给该方法 - 就像您要使用像素数一样?在最小值/最大值上,您需要决定使用哪些汇总统计信息 - 您使用的是算术平均值,如果它适合您,请保留它!
标签: java audio javafx wav amplitude