Android 中音频信号的 FFT 解码器
FFT Decoder for Audio Signal in Android
我正在尝试为 android 发布的项目制作一个解码器
https://github.com/rraval/pied-piper
他们已经在 python 中创建了一个解码器,在 python 中使用 numpy 包非常容易,但在 Java 中我遇到了困难。
python中使用的步骤包括:
def dominant(frame_rate,chunk):
w=numpy.fft.fft(chunk)
numpy.fft.fftfreq(len(chunk))
peak_coeff = numpy.argmax(numpy.abs(w))
peak_freq = freqs[peak_coeff]
return abs(peak_freq * frame_rate) # in Hz
以上代码 returns 块中音频数据的频率 [ ]。
我正在尝试编写实现相同逻辑的 Android 代码。
到目前为止,我的工作如下:
public class MicReadThread3 extends Thread {
static final int HANDSHAKE_START_HZ = 8192;
static final int HANDSHAKE_END_HZ = 8192 + 512;
static final int START_HZ = 1024;
static final int STEP_HZ = 256;
static final int BITS = 4;
static final int FEC_BYTES = 4;
static final int sample_size=8;
boolean callBack_done=false;
private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
private static final int SAMPLE_RATE = 44100; // Hz
private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int CHANNEL_MASK = AudioFormat.CHANNEL_IN_MONO;
private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_MASK, ENCODING);
private static final int blockSize=BUFFER_SIZE;
public MicReadThread3(){
setPriority(Thread.MAX_PRIORITY);
}
@Override
public void run(){
System.out.println("Buffer Size : "+BUFFER_SIZE);
AudioRecord audioRecord=null;
double dom;
byte[] buffer=new byte[blockSize];
short[] bufferShort =new short[blockSize];
audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_MASK, ENCODING, BUFFER_SIZE);
audioRecord.startRecording();
while(true){
audioRecord.read(buffer, 0, blockSize);
dom = dominant(SAMPLE_RATE, buffer);
System.out.println("Dominant="+dom);
if(match(dom,HANDSHAKE_START_HZ)){
System.out.println("Found Handshake start freq :"+dom);
}
if(match(dom,HANDSHAKE_END_HZ)){
System.out.println("Found Handshake end freq :"+dom);
}
}
}
public boolean match(double freq1, double freq2) {
return Math.abs(freq1 - freq2) < 20;
}
public double dominant(int frame_rate, byte[] chunk){
int len=chunk.length;
double[] waveTransformReal=new double[len];
double[] waveTransformImg=new double[len];
for(int i=0;i<len;i++){
waveTransformReal[i]=chunk[i];
}
Fft.transform(waveTransformReal,waveTransformImg);
//Calculating abs
double[] abs=new double[len];
for(int i=0;i<len;i++) {
abs[i] = (Math.sqrt(waveTransformReal[i] * waveTransformReal[i] + waveTransformImg[i] * waveTransformImg[i]));
}
int maxIndex=0;
for(int i=0;i<len;i++) {
if (abs[i] > abs[maxIndex])
maxIndex = i;
}
//frame_rate is sampling freq and len is no. of datapoints
double dominantFrequency=(maxIndex*frame_rate)/len;
return dominantFrequency;
}
}
我用来获取 Fft 的 class 可以在下面给出的 link 中找到:
https://www.nayuki.io/res/free-small-fft-in-multiple-languages/Fft.java
如果它等于握手频率,我必须打印主频率。
但是当我打印这些值时,我得到的只是垃圾频率值,例如 1000,42050,2000,...
在 python 中,代码还不错,但在 android 中,它变得越来越难...请帮忙,我的项目提交必须在下周完成。这只是我项目的一部分,我们因为这个问题而落后了!提前致谢。
我原来的回答太快了
double dominantFrequency=(maxIndex*frame_rate)/len;
参考您的评论,我再次查看,发现 github 代码与您发布的代码之间存在差异:github 请求 8 位音频,这里是 ENCODING_PCM_16BIT.
因此 waveTransformReal[] 中的每个值都只是部分值,因为它取自 chunk[] 字节数据,其中 2 个字节构成完整值。作为快速测试,请尝试使用 ENCODING_PCM_8BIT 并查看是否得到正确的结果。
我正在尝试为 android 发布的项目制作一个解码器 https://github.com/rraval/pied-piper 他们已经在 python 中创建了一个解码器,在 python 中使用 numpy 包非常容易,但在 Java 中我遇到了困难。 python中使用的步骤包括:
def dominant(frame_rate,chunk):
w=numpy.fft.fft(chunk)
numpy.fft.fftfreq(len(chunk))
peak_coeff = numpy.argmax(numpy.abs(w))
peak_freq = freqs[peak_coeff]
return abs(peak_freq * frame_rate) # in Hz
以上代码 returns 块中音频数据的频率 [ ]。
我正在尝试编写实现相同逻辑的 Android 代码。 到目前为止,我的工作如下:
public class MicReadThread3 extends Thread {
static final int HANDSHAKE_START_HZ = 8192;
static final int HANDSHAKE_END_HZ = 8192 + 512;
static final int START_HZ = 1024;
static final int STEP_HZ = 256;
static final int BITS = 4;
static final int FEC_BYTES = 4;
static final int sample_size=8;
boolean callBack_done=false;
private static final int AUDIO_SOURCE = MediaRecorder.AudioSource.MIC;
private static final int SAMPLE_RATE = 44100; // Hz
private static final int ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int CHANNEL_MASK = AudioFormat.CHANNEL_IN_MONO;
private static final int BUFFER_SIZE = AudioRecord.getMinBufferSize(SAMPLE_RATE, CHANNEL_MASK, ENCODING);
private static final int blockSize=BUFFER_SIZE;
public MicReadThread3(){
setPriority(Thread.MAX_PRIORITY);
}
@Override
public void run(){
System.out.println("Buffer Size : "+BUFFER_SIZE);
AudioRecord audioRecord=null;
double dom;
byte[] buffer=new byte[blockSize];
short[] bufferShort =new short[blockSize];
audioRecord = new AudioRecord(AUDIO_SOURCE, SAMPLE_RATE, CHANNEL_MASK, ENCODING, BUFFER_SIZE);
audioRecord.startRecording();
while(true){
audioRecord.read(buffer, 0, blockSize);
dom = dominant(SAMPLE_RATE, buffer);
System.out.println("Dominant="+dom);
if(match(dom,HANDSHAKE_START_HZ)){
System.out.println("Found Handshake start freq :"+dom);
}
if(match(dom,HANDSHAKE_END_HZ)){
System.out.println("Found Handshake end freq :"+dom);
}
}
}
public boolean match(double freq1, double freq2) {
return Math.abs(freq1 - freq2) < 20;
}
public double dominant(int frame_rate, byte[] chunk){
int len=chunk.length;
double[] waveTransformReal=new double[len];
double[] waveTransformImg=new double[len];
for(int i=0;i<len;i++){
waveTransformReal[i]=chunk[i];
}
Fft.transform(waveTransformReal,waveTransformImg);
//Calculating abs
double[] abs=new double[len];
for(int i=0;i<len;i++) {
abs[i] = (Math.sqrt(waveTransformReal[i] * waveTransformReal[i] + waveTransformImg[i] * waveTransformImg[i]));
}
int maxIndex=0;
for(int i=0;i<len;i++) {
if (abs[i] > abs[maxIndex])
maxIndex = i;
}
//frame_rate is sampling freq and len is no. of datapoints
double dominantFrequency=(maxIndex*frame_rate)/len;
return dominantFrequency;
}
}
我用来获取 Fft 的 class 可以在下面给出的 link 中找到: https://www.nayuki.io/res/free-small-fft-in-multiple-languages/Fft.java
如果它等于握手频率,我必须打印主频率。
但是当我打印这些值时,我得到的只是垃圾频率值,例如 1000,42050,2000,...
在 python 中,代码还不错,但在 android 中,它变得越来越难...请帮忙,我的项目提交必须在下周完成。这只是我项目的一部分,我们因为这个问题而落后了!提前致谢。
我原来的回答太快了
double dominantFrequency=(maxIndex*frame_rate)/len;
参考您的评论,我再次查看,发现 github 代码与您发布的代码之间存在差异:github 请求 8 位音频,这里是 ENCODING_PCM_16BIT.
因此 waveTransformReal[] 中的每个值都只是部分值,因为它取自 chunk[] 字节数据,其中 2 个字节构成完整值。作为快速测试,请尝试使用 ENCODING_PCM_8BIT 并查看是否得到正确的结果。