Fur*_*Fry 4 java arrays audio byte fft
我对Java不太熟悉,所以请保持简单.但是,我会尝试理解你发布的所有内容.这是我的问题.
我编写了代码来记录来自外部麦克风的音频并将其存储在.wav中.存储此文件与存档目的相关.我需要做的是存储音频的FFT.
我的方法是将wav文件作为一个字节数组加载并转换它,问题是1.我需要摆脱一个标题,但我应该能够做到这一点而且2.我得到了一个字节数组,但我在网上找到的大多数(如果不是全部)FFT算法都尝试使用复杂/两个双数组修补我的项目工作.
我试图解决这两个问题,最后能够将我的FFT数组绘制成图形,当我发现它只是给我回"0"时..wav文件很好,我可以毫无问题地播放它.我想也许把字节转换成双打对我来说是个问题,所以这是我的方法(我知道它不漂亮)
byte ByteArray[] = Files.readAllBytes(wav_path);
String s = new String(ByteArray);
double[] DoubleArray = toDouble(ByteArray);
// build 2^n array, fill up with zeroes
boolean exp = false;
int i = 0;
int pow = 0;
while (!exp) {
pow = (int) Math.pow(2, i);
if (pow > ByteArray.length) {
exp = true;
} else {
i++;
}
}
System.out.println(pow);
double[] Filledup = new double[pow];
for (int j = 0; j < DoubleArray.length; j++) {
Filledup[j] = DoubleArray[j];
System.out.println(DoubleArray[j]);
}
for (int k = DoubleArray.length; k < Filledup.length; k++) {
Filledup[k] = 0;
}
Run Code Online (Sandbox Code Playgroud)
这是我用来将字节数组转换为双数组的函数:
public static double[] toDouble(byte[] byteArray) {
ByteBuffer byteBuffer = ByteBuffer.wrap(byteArray);
double[] doubles = new double[byteArray.length / 8];
for (int i = 0; i < doubles.length; i++) {
doubles[i] = byteBuffer.getDouble(i * 8);
}
return doubles;
}
Run Code Online (Sandbox Code Playgroud)
标题仍在那里,我知道,但这应该是现在最小的问题.我将我的字节数组转换为双数组,然后用零填充该数组到下一个2的幂,这样FFT实际上可以工作(它需要一个2 ^ n值的数组).我正在使用的FFT算法得到两个双数组作为输入,一个是真实的,另一个是虚部.我读过,为了这个工作,我必须保持虚构数组为空(但它的长度与真实数组相同).
值得一提的是:我用44100 kHz,16位和单声道录音.
如有必要,我将发布我正在使用的FFT.
如果我尝试打印双数组的值,我会得到一些奇怪的结果:
...
-2.0311904060823147E236
-1.3309975624948503E241
1.630738286366793E-260
1.0682002560745842E-255
-5.961832069690704E197
-1.1476447092561027E164
-1.1008407401197794E217
-8.109566204271759E298
-1.6104556241572942E265
-2.2081172620352248E130
NaN
3.643749694745671E-217
-3.9085815506127892E202
-4.0747557114875874E149
...
Run Code Online (Sandbox Code Playgroud)
我知道在某个地方问题在于我忽略了一些我应该知道的非常简单的事情,但我似乎无法找到问题所在.我的问题最终是:我怎样才能让它发挥作用?
在我需要摆脱[...]的方式有一个标题
javax.sound.sampled.AudioInputStream如果要"跳过"标题,则需要使用它来读取文件.无论如何,这对于学习很有用,因为如果您事先不知道确切的格式,则需要标头中的数据来解释字节.
我用44100 kHz,16位和单声道录音.
因此,这几乎肯定意味着文件中的数据被编码为16位整数(short在Java命名法中).
现在,你的ByteBuffer代码假设它已经是64位浮点,这就是你得到奇怪结果的原因.换句话说,您正在重新解释二进制short数据,就像它一样double.
您需要做的是读入short数据然后将其转换为double.
例如,这是一个基本的例程,例如你要做的事情(支持8,16,32和64位有符号整数PCM):
import javax.sound.sampled.*;
import javax.sound.sampled.AudioFormat.Encoding;
import java.io.*;
import java.nio.*;
static double[] readFully(File file)
throws UnsupportedAudioFileException, IOException {
AudioInputStream in = AudioSystem.getAudioInputStream(file);
AudioFormat fmt = in.getFormat();
byte[] bytes;
try {
if(fmt.getEncoding() != Encoding.PCM_SIGNED) {
throw new UnsupportedAudioFileException();
}
// read the data fully
bytes = new byte[in.available()];
in.read(bytes);
} finally {
in.close();
}
int bits = fmt.getSampleSizeInBits();
double max = Math.pow(2, bits - 1);
ByteBuffer bb = ByteBuffer.wrap(bytes);
bb.order(fmt.isBigEndian() ?
ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN);
double[] samples = new double[bytes.length * 8 / bits];
// convert sample-by-sample to a scale of
// -1.0 <= samples[i] < 1.0
for(int i = 0; i < samples.length; ++i) {
switch(bits) {
case 8: samples[i] = ( bb.get() / max );
break;
case 16: samples[i] = ( bb.getShort() / max );
break;
case 32: samples[i] = ( bb.getInt() / max );
break;
case 64: samples[i] = ( bb.getLong() / max );
break;
default: throw new UnsupportedAudioFileException();
}
}
return samples;
}
Run Code Online (Sandbox Code Playgroud)
我正在使用的FFT算法得到两个双数组作为输入,一个是真实的,另一个是虚部.我读过,为了这个工作,我必须保持虚构数组为空(但它的长度与真实数组相同).
那就对了.的实部是从该文件的音频采样阵列,所述虚部等于长度的阵列,用0填充的例如:
double[] realPart = mySamples;
double[] imagPart = new double[realPart.length];
myFft(realPart, imagPart);
Run Code Online (Sandbox Code Playgroud)
更多信息...... "如何使用Java Sound中的音频样本数据?"
| 归档时间: |
|
| 查看次数: |
2074 次 |
| 最近记录: |